blob: 688f89e5355c0159e781d2dacc01b6d62a546f12 [file] [log] [blame]
// Copyright 2014 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/bookmarks/bookmark_promo_controller.h"
#include <memory>
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "components/signin/core/browser/signin_manager.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/pref_names.h"
#include "ios/chrome/browser/signin/signin_manager_factory.h"
#import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
#import "ios/chrome/browser/ui/commands/show_signin_command.h"
#import "ios/chrome/browser/ui/ui_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// Enum is used to record the actions performed by the user on the promo cell.
// |Stars.PromoActions|.
enum {
// Recorded each time the promo cell is presented to the user.
BOOKMARKS_PROMO_ACTION_DISPLAYED,
// The user selected the NO THANKS button.
BOOKMARKS_PROMO_ACTION_DISMISSED,
// The user selected the SIGN-IN button.
BOOKMARKS_PROMO_ACTION_COMPLETED,
// NOTE: Add new promo actions in sources only immediately above this line.
// Also, make sure the enum list for histogram |Stars.PromoActions| in
// histograms.xml is updated with any change in here.
BOOKMARKS_PROMO_ACTION_COUNT
};
// The histogram used to record user actions performed on the promo cell.
const char kBookmarksPromoActionsHistogram[] = "Stars.PromoActions";
class SignInObserver;
} // namespace
@interface BookmarkPromoController () {
bool _isIncognito;
ios::ChromeBrowserState* _browserState;
std::unique_ptr<SignInObserver> _signinObserver;
bool _promoDisplayedRecorded;
}
// Records that the promo was displayed. Can be called several times per
// instance but will effectively record the histogram only once per instance.
- (void)recordPromoDisplayed;
// SignInObserver Callbacks
// Called when a user signs into Google services such as sync.
- (void)googleSigninSucceededWithAccountId:(const std::string&)account_id
username:(const std::string&)username
password:(const std::string&)password;
// Called when the currently signed-in user for a user has been signed out.
- (void)googleSignedOutWithAcountId:(const std::string&)account_id
username:(const std::string&)username;
@end
namespace {
class SignInObserver : public SigninManagerBase::Observer {
public:
SignInObserver(BookmarkPromoController* controller)
: controller_(controller) {}
void GoogleSigninSucceeded(const std::string& account_id,
const std::string& username,
const std::string& password) override {
[controller_ googleSigninSucceededWithAccountId:account_id
username:username
password:password];
}
void GoogleSignedOut(const std::string& account_id,
const std::string& username) override {
[controller_ googleSignedOutWithAcountId:account_id username:username];
}
private:
__weak BookmarkPromoController* controller_;
};
} // namespace
@implementation BookmarkPromoController
@synthesize delegate = _delegate;
@synthesize promoState = _promoState;
+ (void)registerBrowserStatePrefs:(user_prefs::PrefRegistrySyncable*)registry {
registry->RegisterBooleanPref(prefs::kIosBookmarkPromoAlreadySeen, false);
}
- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
delegate:
(id<BookmarkPromoControllerDelegate>)delegate {
self = [super init];
if (self) {
_delegate = delegate;
// Incognito browserState can go away before this class is released, this
// code avoids keeping a pointer to it.
_isIncognito = browserState->IsOffTheRecord();
if (!_isIncognito) {
_browserState = browserState;
_signinObserver.reset(new SignInObserver(self));
SigninManager* signinManager =
ios::SigninManagerFactory::GetForBrowserState(_browserState);
signinManager->AddObserver(_signinObserver.get());
}
[self updatePromoState];
}
return self;
}
- (void)dealloc {
if (!_isIncognito) {
DCHECK(_browserState);
SigninManager* signinManager =
ios::SigninManagerFactory::GetForBrowserState(_browserState);
signinManager->RemoveObserver(_signinObserver.get());
}
}
- (void)showSignIn {
UMA_HISTOGRAM_ENUMERATION(kBookmarksPromoActionsHistogram,
BOOKMARKS_PROMO_ACTION_COMPLETED,
BOOKMARKS_PROMO_ACTION_COUNT);
base::RecordAction(
base::UserMetricsAction("Signin_Signin_FromBookmarkManager"));
ShowSigninCommand* command = [[ShowSigninCommand alloc]
initWithOperation:AUTHENTICATION_OPERATION_SIGNIN
signInAccessPoint:signin_metrics::AccessPoint::
ACCESS_POINT_BOOKMARK_MANAGER];
[self chromeExecuteCommand:command];
}
- (void)hidePromoCell {
DCHECK(!_isIncognito);
DCHECK(_browserState);
UMA_HISTOGRAM_ENUMERATION(kBookmarksPromoActionsHistogram,
BOOKMARKS_PROMO_ACTION_DISMISSED,
BOOKMARKS_PROMO_ACTION_COUNT);
PrefService* prefs = _browserState->GetPrefs();
prefs->SetBoolean(prefs::kIosBookmarkPromoAlreadySeen, true);
self.promoState = NO;
}
- (void)setPromoState:(BOOL)promoState {
if (_promoState != promoState) {
_promoState = promoState;
[self.delegate promoStateChanged:promoState];
}
}
- (void)updatePromoState {
self.promoState = NO;
if (_isIncognito)
return;
DCHECK(_browserState);
PrefService* prefs = _browserState->GetPrefs();
if (!prefs->GetBoolean(prefs::kIosBookmarkPromoAlreadySeen)) {
SigninManager* signinManager =
ios::SigninManagerFactory::GetForBrowserState(_browserState);
self.promoState = !signinManager->IsAuthenticated();
if (self.promoState)
[self recordPromoDisplayed];
}
}
#pragma mark - Private
- (void)chromeExecuteCommand:(id)sender {
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate respondsToSelector:@selector(chromeExecuteCommand:)])
[delegate chromeExecuteCommand:sender];
}
- (void)recordPromoDisplayed {
if (_promoDisplayedRecorded)
return;
_promoDisplayedRecorded = YES;
UMA_HISTOGRAM_ENUMERATION(kBookmarksPromoActionsHistogram,
BOOKMARKS_PROMO_ACTION_DISPLAYED,
BOOKMARKS_PROMO_ACTION_COUNT);
base::RecordAction(
base::UserMetricsAction("Signin_Impression_FromBookmarkManager"));
}
#pragma mark - SignInObserver
// Called when a user signs into Google services such as sync.
- (void)googleSigninSucceededWithAccountId:(const std::string&)account_id
username:(const std::string&)username
password:(const std::string&)password {
self.promoState = NO;
}
// Called when the currently signed-in user for a user has been signed out.
- (void)googleSignedOutWithAcountId:(const std::string&)account_id
username:(const std::string&)username {
[self updatePromoState];
}
@end