OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h" | 5 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <limits> | 10 #include <limits> |
11 #include <string> | 11 #include <string> |
12 #include <vector> | 12 #include <vector> |
13 | 13 |
| 14 #include "base/metrics/histogram_macros.h" |
14 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
15 #include "base/time/default_clock.h" | 16 #include "base/time/default_clock.h" |
16 #include "chrome/browser/password_manager/password_store_factory.h" | 17 #include "chrome/browser/password_manager/password_store_factory.h" |
17 #include "chrome/browser/profiles/profile.h" | 18 #include "chrome/browser/profiles/profile.h" |
18 #include "chrome/browser/sync/profile_sync_service_factory.h" | 19 #include "chrome/browser/sync/profile_sync_service_factory.h" |
19 #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h" | 20 #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h" |
20 #include "chrome/browser/ui/passwords/passwords_model_delegate.h" | 21 #include "chrome/browser/ui/passwords/passwords_model_delegate.h" |
21 #include "chrome/grit/chromium_strings.h" | 22 #include "chrome/grit/chromium_strings.h" |
22 #include "chrome/grit/generated_resources.h" | 23 #include "chrome/grit/generated_resources.h" |
23 #include "components/browser_sync/browser/profile_sync_service.h" | 24 #include "components/browser_sync/browser/profile_sync_service.h" |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 void set_dismissal_reason( | 90 void set_dismissal_reason( |
90 password_manager::metrics_util::UIDismissalReason reason) { | 91 password_manager::metrics_util::UIDismissalReason reason) { |
91 dismissal_reason_ = reason; | 92 dismissal_reason_ = reason; |
92 } | 93 } |
93 | 94 |
94 void set_update_password_submission_event( | 95 void set_update_password_submission_event( |
95 password_manager::metrics_util::UpdatePasswordSubmissionEvent event) { | 96 password_manager::metrics_util::UpdatePasswordSubmissionEvent event) { |
96 update_password_submission_event_ = event; | 97 update_password_submission_event_ = event; |
97 } | 98 } |
98 | 99 |
| 100 void set_sign_in_promo_dismissal_reason( |
| 101 password_manager::metrics_util::SyncSignInUserAction reason) { |
| 102 sign_in_promo_dismissal_reason_ = reason; |
| 103 } |
| 104 |
99 void SetClockForTesting(std::unique_ptr<base::Clock> clock) { | 105 void SetClockForTesting(std::unique_ptr<base::Clock> clock) { |
100 clock_ = std::move(clock); | 106 clock_ = std::move(clock); |
101 } | 107 } |
102 | 108 |
103 private: | 109 private: |
104 // The way the bubble appeared. | 110 // The way the bubble appeared. |
105 const password_manager::metrics_util::UIDisplayDisposition | 111 const password_manager::metrics_util::UIDisplayDisposition |
106 display_disposition_; | 112 display_disposition_; |
107 | 113 |
108 // Dismissal reason for a bubble. | 114 // Dismissal reason for a bubble. |
109 password_manager::metrics_util::UIDismissalReason dismissal_reason_; | 115 password_manager::metrics_util::UIDismissalReason dismissal_reason_; |
110 | 116 |
111 // Dismissal reason for the update bubble. | 117 // Dismissal reason for the update bubble. |
112 password_manager::metrics_util::UpdatePasswordSubmissionEvent | 118 password_manager::metrics_util::UpdatePasswordSubmissionEvent |
113 update_password_submission_event_; | 119 update_password_submission_event_; |
114 | 120 |
| 121 // Dismissal reason for the Chrome Sign in bubble. |
| 122 password_manager::metrics_util::SyncSignInUserAction |
| 123 sign_in_promo_dismissal_reason_; |
| 124 |
115 // Current statistics for the save password bubble; | 125 // Current statistics for the save password bubble; |
116 password_manager::InteractionsStats interaction_stats_; | 126 password_manager::InteractionsStats interaction_stats_; |
117 | 127 |
118 // Used to retrieve the current time, in base::Time units. | 128 // Used to retrieve the current time, in base::Time units. |
119 std::unique_ptr<base::Clock> clock_; | 129 std::unique_ptr<base::Clock> clock_; |
120 | 130 |
121 DISALLOW_COPY_AND_ASSIGN(InteractionKeeper); | 131 DISALLOW_COPY_AND_ASSIGN(InteractionKeeper); |
122 }; | 132 }; |
123 | 133 |
124 ManagePasswordsBubbleModel::InteractionKeeper::InteractionKeeper( | 134 ManagePasswordsBubbleModel::InteractionKeeper::InteractionKeeper( |
125 password_manager::InteractionsStats stats, | 135 password_manager::InteractionsStats stats, |
126 password_manager::metrics_util::UIDisplayDisposition display_disposition) | 136 password_manager::metrics_util::UIDisplayDisposition display_disposition) |
127 : display_disposition_(display_disposition), | 137 : display_disposition_(display_disposition), |
128 dismissal_reason_(metrics_util::NO_DIRECT_INTERACTION), | 138 dismissal_reason_(metrics_util::NO_DIRECT_INTERACTION), |
129 update_password_submission_event_(metrics_util::NO_UPDATE_SUBMISSION), | 139 update_password_submission_event_(metrics_util::NO_UPDATE_SUBMISSION), |
| 140 sign_in_promo_dismissal_reason_(metrics_util::CHROME_SIGNIN_DISMISSED), |
130 interaction_stats_(std::move(stats)), | 141 interaction_stats_(std::move(stats)), |
131 clock_(new base::DefaultClock) { | 142 clock_(new base::DefaultClock) {} |
132 } | |
133 | 143 |
134 void ManagePasswordsBubbleModel::InteractionKeeper::ReportInteractions( | 144 void ManagePasswordsBubbleModel::InteractionKeeper::ReportInteractions( |
135 const ManagePasswordsBubbleModel* model) { | 145 const ManagePasswordsBubbleModel* model) { |
136 if (model->state() == password_manager::ui::PENDING_PASSWORD_STATE) { | 146 if (model->state() == password_manager::ui::PENDING_PASSWORD_STATE) { |
137 Profile* profile = model->GetProfile(); | 147 Profile* profile = model->GetProfile(); |
138 if (profile) { | 148 if (profile) { |
139 if (GetSmartLockBrandingState(profile) == | 149 if (GetSmartLockBrandingState(profile) == |
140 password_bubble_experiment::SmartLockBranding::FULL) { | 150 password_bubble_experiment::SmartLockBranding::FULL) { |
141 password_bubble_experiment::RecordSavePromptFirstRunExperienceWasShown( | 151 password_bubble_experiment::RecordSavePromptFirstRunExperienceWasShown( |
142 profile->GetPrefs()); | 152 profile->GetPrefs()); |
143 } | 153 } |
144 if (dismissal_reason_ == metrics_util::NO_DIRECT_INTERACTION && | 154 if (dismissal_reason_ == metrics_util::NO_DIRECT_INTERACTION && |
145 display_disposition_ == | 155 display_disposition_ == |
146 metrics_util::AUTOMATIC_WITH_PASSWORD_PENDING) { | 156 metrics_util::AUTOMATIC_WITH_PASSWORD_PENDING) { |
147 if (interaction_stats_.dismissal_count < | 157 if (interaction_stats_.dismissal_count < |
148 std::numeric_limits<decltype( | 158 std::numeric_limits<decltype( |
149 interaction_stats_.dismissal_count)>::max()) | 159 interaction_stats_.dismissal_count)>::max()) |
150 interaction_stats_.dismissal_count++; | 160 interaction_stats_.dismissal_count++; |
151 interaction_stats_.update_time = clock_->Now(); | 161 interaction_stats_.update_time = clock_->Now(); |
152 password_manager::PasswordStore* password_store = | 162 password_manager::PasswordStore* password_store = |
153 PasswordStoreFactory::GetForProfile( | 163 PasswordStoreFactory::GetForProfile( |
154 profile, ServiceAccessType::IMPLICIT_ACCESS).get(); | 164 profile, ServiceAccessType::IMPLICIT_ACCESS).get(); |
155 password_store->AddSiteStats(interaction_stats_); | 165 password_store->AddSiteStats(interaction_stats_); |
156 } | 166 } |
157 } | 167 } |
158 } | 168 } |
159 | 169 |
160 if (model->state() != password_manager::ui::PENDING_PASSWORD_UPDATE_STATE) { | 170 if (model->state() == password_manager::ui::CHROME_SIGN_IN_PROMO_STATE) { |
| 171 metrics_util::LogAutoSigninPromoUserAction(sign_in_promo_dismissal_reason_); |
| 172 if (sign_in_promo_dismissal_reason_ == |
| 173 password_manager::metrics_util::CHROME_SIGNIN_OK || |
| 174 sign_in_promo_dismissal_reason_ == |
| 175 password_manager::metrics_util::CHROME_SIGNIN_CANCEL) { |
| 176 DCHECK(model->web_contents()); |
| 177 int show_count = model->GetProfile()->GetPrefs()->GetInteger( |
| 178 password_manager::prefs::kNumberSignInPasswordPromoShown); |
| 179 UMA_HISTOGRAM_COUNTS_100("PasswordManager.SignInPromoCountTilClick", |
| 180 show_count); |
| 181 } |
| 182 } else if (model->state() != |
| 183 password_manager::ui::PENDING_PASSWORD_UPDATE_STATE) { |
161 // We have separate metrics for the Update bubble so do not record dismissal | 184 // We have separate metrics for the Update bubble so do not record dismissal |
162 // reason for it. | 185 // reason for it. |
163 metrics_util::LogUIDismissalReason(dismissal_reason_); | 186 metrics_util::LogUIDismissalReason(dismissal_reason_); |
164 } | 187 } |
165 | 188 |
166 PasswordsModelDelegate* delegate = model->web_contents() | 189 if (model->state() == password_manager::ui::PENDING_PASSWORD_UPDATE_STATE || |
167 ? PasswordsModelDelegateFromWebContents(model->web_contents()) | 190 model->state() == password_manager::ui::PENDING_PASSWORD_STATE) { |
168 : nullptr; | 191 if (update_password_submission_event_ == |
169 // Check if this was update password and record update statistics. | 192 metrics_util::NO_UPDATE_SUBMISSION) { |
170 if (update_password_submission_event_ == metrics_util::NO_UPDATE_SUBMISSION && | 193 update_password_submission_event_ = |
171 (model->state() == password_manager::ui::PENDING_PASSWORD_UPDATE_STATE || | 194 model->GetUpdateDismissalReason(NO_INTERACTION); |
172 model->state() == password_manager::ui::PENDING_PASSWORD_STATE)) { | 195 PasswordsModelDelegate* delegate = |
173 update_password_submission_event_ = | 196 model->web_contents() |
174 model->GetUpdateDismissalReason(NO_INTERACTION); | 197 ? PasswordsModelDelegateFromWebContents(model->web_contents()) |
175 if (model->state() == password_manager::ui::PENDING_PASSWORD_UPDATE_STATE && | 198 : nullptr; |
176 delegate) | 199 if (delegate && |
177 delegate->OnNoInteractionOnUpdate(); | 200 model->state() == password_manager::ui::PENDING_PASSWORD_UPDATE_STATE) |
| 201 delegate->OnNoInteractionOnUpdate(); |
| 202 } |
| 203 |
| 204 if (update_password_submission_event_ != metrics_util::NO_UPDATE_SUBMISSION) |
| 205 LogUpdatePasswordSubmissionEvent(update_password_submission_event_); |
178 } | 206 } |
179 if (update_password_submission_event_ != metrics_util::NO_UPDATE_SUBMISSION) | |
180 LogUpdatePasswordSubmissionEvent(update_password_submission_event_); | |
181 } | 207 } |
182 | 208 |
183 ManagePasswordsBubbleModel::ManagePasswordsBubbleModel( | 209 ManagePasswordsBubbleModel::ManagePasswordsBubbleModel( |
184 content::WebContents* web_contents, | 210 content::WebContents* web_contents, |
185 DisplayReason display_reason) | 211 DisplayReason display_reason) |
186 : content::WebContentsObserver(web_contents), | 212 : content::WebContentsObserver(web_contents), |
187 password_overridden_(false) { | 213 password_overridden_(false) { |
188 PasswordsModelDelegate* delegate = | 214 PasswordsModelDelegate* delegate = |
189 PasswordsModelDelegateFromWebContents(web_contents); | 215 PasswordsModelDelegateFromWebContents(web_contents); |
190 | 216 |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
389 PasswordStoreFactory::GetForProfile( | 415 PasswordStoreFactory::GetForProfile( |
390 profile, ServiceAccessType::EXPLICIT_ACCESS).get(); | 416 profile, ServiceAccessType::EXPLICIT_ACCESS).get(); |
391 DCHECK(password_store); | 417 DCHECK(password_store); |
392 if (action == REMOVE_PASSWORD) | 418 if (action == REMOVE_PASSWORD) |
393 password_store->RemoveLogin(password_form); | 419 password_store->RemoveLogin(password_form); |
394 else | 420 else |
395 password_store->AddLogin(password_form); | 421 password_store->AddLogin(password_form); |
396 } | 422 } |
397 | 423 |
398 void ManagePasswordsBubbleModel::OnSignInToChromeClicked() { | 424 void ManagePasswordsBubbleModel::OnSignInToChromeClicked() { |
399 | 425 interaction_keeper_->set_sign_in_promo_dismissal_reason( |
| 426 metrics_util::CHROME_SIGNIN_OK); |
| 427 GetProfile()->GetPrefs()->SetBoolean( |
| 428 password_manager::prefs::kWasSignInPasswordPromoClicked, true); |
| 429 PasswordsModelDelegateFromWebContents(web_contents()) |
| 430 ->NavigateToChromeSignIn(); |
400 } | 431 } |
401 | 432 |
402 void ManagePasswordsBubbleModel::OnSkipSignInClicked() { | 433 void ManagePasswordsBubbleModel::OnSkipSignInClicked() { |
403 | 434 interaction_keeper_->set_sign_in_promo_dismissal_reason( |
| 435 metrics_util::CHROME_SIGNIN_CANCEL); |
| 436 GetProfile()->GetPrefs()->SetBoolean( |
| 437 password_manager::prefs::kWasSignInPasswordPromoClicked, true); |
404 } | 438 } |
405 | 439 |
406 Profile* ManagePasswordsBubbleModel::GetProfile() const { | 440 Profile* ManagePasswordsBubbleModel::GetProfile() const { |
407 return GetProfileFromWebContents(web_contents()); | 441 return GetProfileFromWebContents(web_contents()); |
408 } | 442 } |
409 | 443 |
410 bool ManagePasswordsBubbleModel::ShouldShowMultipleAccountUpdateUI() const { | 444 bool ManagePasswordsBubbleModel::ShouldShowMultipleAccountUpdateUI() const { |
411 return state_ == password_manager::ui::PENDING_PASSWORD_UPDATE_STATE && | 445 return state_ == password_manager::ui::PENDING_PASSWORD_UPDATE_STATE && |
412 local_credentials_.size() > 1 && !password_overridden_; | 446 local_credentials_.size() > 1 && !password_overridden_; |
413 } | 447 } |
414 | 448 |
415 bool ManagePasswordsBubbleModel::ShouldShowGoogleSmartLockWelcome() const { | 449 bool ManagePasswordsBubbleModel::ShouldShowGoogleSmartLockWelcome() const { |
416 Profile* profile = GetProfile(); | 450 Profile* profile = GetProfile(); |
417 if (GetSmartLockBrandingState(profile) == | 451 if (GetSmartLockBrandingState(profile) == |
418 password_bubble_experiment::SmartLockBranding::FULL) { | 452 password_bubble_experiment::SmartLockBranding::FULL) { |
419 PrefService* prefs = profile->GetPrefs(); | 453 PrefService* prefs = profile->GetPrefs(); |
420 return !prefs->GetBoolean( | 454 return !prefs->GetBoolean( |
421 password_manager::prefs::kWasSavePrompFirstRunExperienceShown); | 455 password_manager::prefs::kWasSavePrompFirstRunExperienceShown); |
422 } | 456 } |
423 return false; | 457 return false; |
424 } | 458 } |
425 | 459 |
426 bool ManagePasswordsBubbleModel::ReplaceToShowSignInPromoIfNeeded() { | 460 bool ManagePasswordsBubbleModel::ReplaceToShowSignInPromoIfNeeded() { |
427 DCHECK_EQ(password_manager::ui::PENDING_PASSWORD_STATE, state_); | 461 DCHECK_EQ(password_manager::ui::PENDING_PASSWORD_STATE, state_); |
428 if (false /*TODO(crbug.com/615825): there will be a real condition soon*/) { | 462 PrefService* prefs = GetProfile()->GetPrefs(); |
| 463 if (password_bubble_experiment::ShouldShowChromeSignInPasswordPromo(prefs)) { |
| 464 interaction_keeper_->ReportInteractions(this); |
429 title_brand_link_range_ = gfx::Range(); | 465 title_brand_link_range_ = gfx::Range(); |
430 title_ = l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SIGNIN_PROMO_TITLE); | 466 title_ = l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SIGNIN_PROMO_TITLE); |
431 state_ = password_manager::ui::CHROME_SIGN_IN_PROMO_STATE; | 467 state_ = password_manager::ui::CHROME_SIGN_IN_PROMO_STATE; |
| 468 int show_count = prefs->GetInteger( |
| 469 password_manager::prefs::kNumberSignInPasswordPromoShown); |
| 470 prefs->SetInteger(password_manager::prefs::kNumberSignInPasswordPromoShown, |
| 471 show_count + 1); |
432 return true; | 472 return true; |
433 } | 473 } |
434 return false; | 474 return false; |
435 } | 475 } |
436 | 476 |
437 void ManagePasswordsBubbleModel::SetClockForTesting( | 477 void ManagePasswordsBubbleModel::SetClockForTesting( |
438 std::unique_ptr<base::Clock> clock) { | 478 std::unique_ptr<base::Clock> clock) { |
439 interaction_keeper_->SetClockForTesting(std::move(clock)); | 479 interaction_keeper_->SetClockForTesting(std::move(clock)); |
440 } | 480 } |
441 | 481 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
482 return metrics_util::NO_UPDATE_SUBMISSION; | 522 return metrics_util::NO_UPDATE_SUBMISSION; |
483 } | 523 } |
484 if (state_ != password_manager::ui::PENDING_PASSWORD_UPDATE_STATE) | 524 if (state_ != password_manager::ui::PENDING_PASSWORD_UPDATE_STATE) |
485 return metrics_util::NO_UPDATE_SUBMISSION; | 525 return metrics_util::NO_UPDATE_SUBMISSION; |
486 if (password_overridden_) | 526 if (password_overridden_) |
487 return update_events[3][behavior]; | 527 return update_events[3][behavior]; |
488 if (ShouldShowMultipleAccountUpdateUI()) | 528 if (ShouldShowMultipleAccountUpdateUI()) |
489 return update_events[2][behavior]; | 529 return update_events[2][behavior]; |
490 return update_events[1][behavior]; | 530 return update_events[1][behavior]; |
491 } | 531 } |
OLD | NEW |