Chromium Code Reviews| 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 // web_contents() can't be nullptr in this block. | |
|
vabr (Chromium)
2016/06/06 15:23:14
nit: The standard way to say this is:
DCHECK(web_c
vasilii
2016/06/06 15:45:14
Done.
| |
| 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 |