d58dcee2b21d92d0818a625d7c70ddceb2090a73
[platform/framework/web/crosswalk.git] / src / chrome / browser / metrics / signin_status_metrics_provider.cc
1 // Copyright 2014 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 #include "chrome/browser/metrics/signin_status_metrics_provider.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/metrics/histogram.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/profiles/profile_info_cache.h"
16 #include "chrome/browser/profiles/profile_manager.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/browser_list.h"
19 #include "components/signin/core/browser/signin_manager.h"
20
21 #if !defined(OS_ANDROID)
22 #include "chrome/browser/ui/browser_finder.h"
23 #endif
24
25 namespace {
26
27 // The event of calling function ComputeCurrentSigninStatus and the errors
28 // occurred during the function execution.
29 enum ComputeSigninStatus {
30   ENTERED_COMPUTE_SIGNIN_STATUS,
31   ERROR_COMPUTE_SIGNIN_STATUS,
32   COMPUTE_SIGNIN_STATUS_MAX,
33 };
34
35 void RecordComputeSigninStatusHistogram(ComputeSigninStatus status) {
36   UMA_HISTOGRAM_ENUMERATION("UMA.ComputeCurrentSigninStatus", status,
37                             COMPUTE_SIGNIN_STATUS_MAX);
38 }
39
40 }  // namespace
41
42 SigninStatusMetricsProvider::SigninStatusMetricsProvider(bool is_test)
43     : signin_status_(UNKNOWN_SIGNIN_STATUS),
44       scoped_observer_(this),
45       is_test_(is_test),
46       weak_ptr_factory_(this) {
47   if (is_test_)
48     return;
49
50   // Postpone the initialization until all threads are created.
51   base::MessageLoop::current()->PostTask(
52       FROM_HERE,
53       base::Bind(&SigninStatusMetricsProvider::Initialize,
54                  weak_ptr_factory_.GetWeakPtr()));
55 }
56
57 SigninStatusMetricsProvider::~SigninStatusMetricsProvider() {
58   if (is_test_)
59     return;
60
61 #if !defined(OS_ANDROID)
62   BrowserList::RemoveObserver(this);
63 #endif
64
65   SigninManagerFactory* factory = SigninManagerFactory::GetInstance();
66   if (factory)
67     factory->RemoveObserver(this);
68 }
69
70 void SigninStatusMetricsProvider::RecordSigninStatusHistogram() {
71   UMA_HISTOGRAM_ENUMERATION(
72       "UMA.ProfileSignInStatus", signin_status_, SIGNIN_STATUS_MAX);
73   // After a histogram value is recorded, a new UMA session will be started, so
74   // we need to re-check the current sign-in status regardless of the previous
75   // recorded |signin_status_| value.
76   ComputeCurrentSigninStatus();
77 }
78
79 // static
80 SigninStatusMetricsProvider* SigninStatusMetricsProvider::CreateInstance() {
81   return new SigninStatusMetricsProvider(false);
82 }
83
84 void SigninStatusMetricsProvider::OnBrowserAdded(Browser* browser) {
85   if (signin_status_ == MIXED_SIGNIN_STATUS)
86     return;
87
88   SigninManager* manager = SigninManagerFactory::GetForProfile(
89       browser->profile());
90
91   // Nothing will change if the opened browser is in incognito mode.
92   if (!manager)
93     return;
94
95   const bool signed_in = !manager->GetAuthenticatedUsername().empty();
96   UpdateStatusWhenBrowserAdded(signed_in);
97 }
98
99 void SigninStatusMetricsProvider::SigninManagerCreated(
100     SigninManagerBase* manager) {
101   // Whenever a new profile is created, a new SigninManagerBase will be created
102   // for it. This ensures that all sign-in or sign-out actions of all opened
103   // profiles are being monitored.
104   scoped_observer_.Add(manager);
105
106   // If the status is unknown, it means this is the first created
107   // SigninManagerBase and the corresponding profile should be the only opened
108   // profile.
109   if (signin_status_ == UNKNOWN_SIGNIN_STATUS) {
110     size_t signed_in_count =
111         manager->GetAuthenticatedUsername().empty() ? 0 : 1;
112     UpdateInitialSigninStatus(1, signed_in_count);
113   }
114 }
115
116 void SigninStatusMetricsProvider::SigninManagerShutdown(
117     SigninManagerBase* manager) {
118   if (scoped_observer_.IsObserving(manager))
119     scoped_observer_.Remove(manager);
120 }
121
122 void SigninStatusMetricsProvider::GoogleSigninSucceeded(
123     const std::string& username,
124     const std::string& password) {
125   if (signin_status_ == ALL_PROFILES_NOT_SIGNED_IN)
126     signin_status_ = MIXED_SIGNIN_STATUS;
127 }
128
129 void SigninStatusMetricsProvider::GoogleSignedOut(const std::string& username) {
130   if (signin_status_ == ALL_PROFILES_SIGNED_IN)
131     signin_status_ = MIXED_SIGNIN_STATUS;
132 }
133
134 void SigninStatusMetricsProvider::Initialize() {
135   // Add observers.
136 #if !defined(OS_ANDROID)
137   // On Android, there is always only one profile in any situation, opening new
138   // windows (which is possible with only some Android devices) will not change
139   // the opened profiles signin status.
140   BrowserList::AddObserver(this);
141 #endif
142   SigninManagerFactory::GetInstance()->AddObserver(this);
143
144   // Start observing all already-created SigninManagers.
145   ProfileManager* profile_manager = g_browser_process->profile_manager();
146   std::vector<Profile*> profiles = profile_manager->GetLoadedProfiles();
147   for (size_t i = 0; i < profiles.size(); ++i) {
148     SigninManager* manager = SigninManagerFactory::GetForProfileIfExists(
149         profiles[i]);
150     if (manager) {
151       DCHECK(!scoped_observer_.IsObserving(manager));
152       scoped_observer_.Add(manager);
153     }
154   }
155
156   // It is possible that when this object is created, no SigninManager is
157   // created yet, for example, when Chrome is opened for the first time after
158   // installation on desktop, or when Chrome on Android is loaded into memory.
159   if (profiles.empty()) {
160     signin_status_ = UNKNOWN_SIGNIN_STATUS;
161   } else {
162     ComputeCurrentSigninStatus();
163   }
164 }
165
166 void SigninStatusMetricsProvider::UpdateInitialSigninStatus(
167     size_t total_count,
168     size_t signed_in_profiles_count) {
169   RecordComputeSigninStatusHistogram(ENTERED_COMPUTE_SIGNIN_STATUS);
170
171   if (total_count == 0) {
172     // This should never happen. If it does, record it in histogram.
173     RecordComputeSigninStatusHistogram(ERROR_COMPUTE_SIGNIN_STATUS);
174     signin_status_ = UNKNOWN_SIGNIN_STATUS;
175   } else if (signed_in_profiles_count == 0) {
176     signin_status_ = ALL_PROFILES_NOT_SIGNED_IN;
177   } else if (total_count == signed_in_profiles_count) {
178     signin_status_ = ALL_PROFILES_SIGNED_IN;
179   } else {
180     signin_status_ = MIXED_SIGNIN_STATUS;
181   }
182 }
183
184 void SigninStatusMetricsProvider::UpdateStatusWhenBrowserAdded(bool signed_in) {
185 #if !defined(OS_ANDROID)
186   if ((signin_status_ == ALL_PROFILES_NOT_SIGNED_IN && signed_in) ||
187       (signin_status_ == ALL_PROFILES_SIGNED_IN && !signed_in)) {
188     signin_status_ = MIXED_SIGNIN_STATUS;
189   }
190 #endif
191 }
192
193 void SigninStatusMetricsProvider::ComputeCurrentSigninStatus() {
194   // Get the sign-in status of all currently open profiles. Sign-in status is
195   // indicated by its username. When username is not empty, the profile is
196   // signed-in.
197   ProfileManager* profile_manager = g_browser_process->profile_manager();
198   std::vector<Profile*> profile_list = profile_manager->GetLoadedProfiles();
199
200   size_t opened_profiles_count = 0;
201   size_t signed_in_profiles_count = 0;
202
203   for (size_t i = 0; i < profile_list.size(); ++i) {
204 #if !defined(OS_ANDROID)
205     if (chrome::GetTotalBrowserCountForProfile(profile_list[i]) == 0) {
206       // The profile is loaded, but there's no opened browser for this profile.
207       continue;
208     }
209 #endif
210     opened_profiles_count++;
211     SigninManager* manager = SigninManagerFactory::GetForProfile(
212         profile_list[i]->GetOriginalProfile());
213     if (manager && !manager->GetAuthenticatedUsername().empty())
214       signed_in_profiles_count++;
215   }
216   UpdateInitialSigninStatus(opened_profiles_count, signed_in_profiles_count);
217 }
218
219 SigninStatusMetricsProvider::ProfilesSigninStatus
220 SigninStatusMetricsProvider::GetSigninStatusForTesting() {
221   return signin_status_;
222 }