#include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
-#include "chrome/browser/password_manager/password_store.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
#include "chrome/browser/password_manager/password_store_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/chrome_pages.h"
-#include "chrome/browser/ui/passwords/manage_passwords_bubble_ui_controller.h"
-#include "chrome/common/url_constants.h"
+#include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
+#include "components/password_manager/core/browser/password_store.h"
+#include "components/password_manager/core/common/password_manager_ui.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
-using content::WebContents;
using autofill::PasswordFormMap;
+using content::WebContents;
+namespace metrics_util = password_manager::metrics_util;
+
+namespace {
+
+void SetupLinkifiedText(const base::string16& string_with_separator,
+ base::string16* text,
+ gfx::Range* link_range) {
+ std::vector<base::string16> pieces;
+ base::SplitStringDontTrim(string_with_separator,
+ '|', // separator
+ &pieces);
+ DCHECK_EQ(3u, pieces.size());
+ *link_range = gfx::Range(pieces[0].size(),
+ pieces[0].size() + pieces[1].size());
+ *text = JoinString(pieces, base::string16());
+}
+
+} // namespace
ManagePasswordsBubbleModel::ManagePasswordsBubbleModel(
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
- web_contents_(web_contents) {
- ManagePasswordsBubbleUIController* manage_passwords_bubble_ui_controller =
- ManagePasswordsBubbleUIController::FromWebContents(web_contents_);
-
- password_submitted_ =
- manage_passwords_bubble_ui_controller->password_submitted();
- if (password_submitted_) {
- if (manage_passwords_bubble_ui_controller->password_to_be_saved())
- manage_passwords_bubble_state_ = PASSWORD_TO_BE_SAVED;
- else
- manage_passwords_bubble_state_ = MANAGE_PASSWORDS_AFTER_SAVING;
+ display_disposition_(
+ metrics_util::AUTOMATIC_WITH_PASSWORD_PENDING),
+ dismissal_reason_(metrics_util::NOT_DISPLAYED) {
+ ManagePasswordsUIController* controller =
+ ManagePasswordsUIController::FromWebContents(web_contents);
+
+ // TODO(mkwst): Reverse this logic. The controller should populate the model
+ // directly rather than the model pulling from the controller. Perhaps like
+ // `controller->PopulateModel(this)`.
+ state_ = controller->state();
+ if (password_manager::ui::IsPendingState(state_))
+ pending_credentials_ = controller->PendingCredentials();
+ best_matches_ = controller->best_matches();
+
+ if (password_manager::ui::IsPendingState(state_)) {
+ title_ = l10n_util::GetStringUTF16(IDS_SAVE_PASSWORD);
+ } else if (state_ == password_manager::ui::BLACKLIST_STATE) {
+ title_ = l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_BLACKLISTED_TITLE);
+ } else if (state_ == password_manager::ui::CONFIRMATION_STATE) {
+ title_ =
+ l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TITLE);
} else {
- manage_passwords_bubble_state_ = MANAGE_PASSWORDS;
+ title_ = l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_TITLE);
}
- title_ = l10n_util::GetStringUTF16(
- (manage_passwords_bubble_state_ == PASSWORD_TO_BE_SAVED) ?
- IDS_SAVE_PASSWORD : IDS_MANAGE_PASSWORDS);
- if (password_submitted_) {
- pending_credentials_ =
- manage_passwords_bubble_ui_controller->pending_credentials();
- }
- best_matches_ = manage_passwords_bubble_ui_controller->best_matches();
+ SetupLinkifiedText(
+ l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TEXT),
+ &save_confirmation_text_,
+ &save_confirmation_link_range_);
+
manage_link_ =
l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_MANAGE_PASSWORDS_LINK);
}
ManagePasswordsBubbleModel::~ManagePasswordsBubbleModel() {}
-void ManagePasswordsBubbleModel::OnCancelClicked() {
- manage_passwords_bubble_state_ = PASSWORD_TO_BE_SAVED;
+void ManagePasswordsBubbleModel::OnBubbleShown(
+ ManagePasswordsBubble::DisplayReason reason) {
+ if (reason == ManagePasswordsBubble::USER_ACTION) {
+ if (password_manager::ui::IsPendingState(state_)) {
+ display_disposition_ = metrics_util::MANUAL_WITH_PASSWORD_PENDING;
+ } else if (state_ == password_manager::ui::BLACKLIST_STATE) {
+ display_disposition_ = metrics_util::MANUAL_BLACKLISTED;
+ } else {
+ display_disposition_ = metrics_util::MANUAL_MANAGE_PASSWORDS;
+ }
+ } else {
+ if (state_ == password_manager::ui::CONFIRMATION_STATE) {
+ display_disposition_ =
+ metrics_util::AUTOMATIC_GENERATED_PASSWORD_CONFIRMATION;
+ } else {
+ display_disposition_ = metrics_util::AUTOMATIC_WITH_PASSWORD_PENDING;
+ }
+ }
+ metrics_util::LogUIDisplayDisposition(display_disposition_);
+
+ // Default to a dismissal reason of "no interaction". If the user interacts
+ // with the button in such a way that it closes, we'll reset this value
+ // accordingly.
+ dismissal_reason_ = metrics_util::NO_DIRECT_INTERACTION;
+}
+
+void ManagePasswordsBubbleModel::OnBubbleHidden() {
+ if (dismissal_reason_ == metrics_util::NOT_DISPLAYED)
+ return;
+
+ metrics_util::LogUIDismissalReason(dismissal_reason_);
+}
+
+void ManagePasswordsBubbleModel::OnNopeClicked() {
+ dismissal_reason_ = metrics_util::CLICKED_NOPE;
+ state_ = password_manager::ui::PENDING_PASSWORD_STATE;
+}
+
+void ManagePasswordsBubbleModel::OnNeverForThisSiteClicked() {
+ dismissal_reason_ = metrics_util::CLICKED_NEVER;
+ ManagePasswordsUIController* manage_passwords_ui_controller =
+ ManagePasswordsUIController::FromWebContents(web_contents());
+ manage_passwords_ui_controller->NeverSavePassword();
+ state_ = password_manager::ui::BLACKLIST_STATE;
+}
+
+void ManagePasswordsBubbleModel::OnUnblacklistClicked() {
+ dismissal_reason_ = metrics_util::CLICKED_UNBLACKLIST;
+ ManagePasswordsUIController* manage_passwords_ui_controller =
+ ManagePasswordsUIController::FromWebContents(web_contents());
+ manage_passwords_ui_controller->UnblacklistSite();
+ state_ = password_manager::ui::MANAGE_STATE;
}
void ManagePasswordsBubbleModel::OnSaveClicked() {
- ManagePasswordsBubbleUIController* manage_passwords_bubble_ui_controller =
- ManagePasswordsBubbleUIController::FromWebContents(web_contents_);
- manage_passwords_bubble_ui_controller->SavePassword();
- manage_passwords_bubble_ui_controller->unset_password_to_be_saved();
- manage_passwords_bubble_state_ = MANAGE_PASSWORDS_AFTER_SAVING;
+ dismissal_reason_ = metrics_util::CLICKED_SAVE;
+ ManagePasswordsUIController* manage_passwords_ui_controller =
+ ManagePasswordsUIController::FromWebContents(web_contents());
+ manage_passwords_ui_controller->SavePassword();
+ state_ = password_manager::ui::MANAGE_STATE;
+}
+
+void ManagePasswordsBubbleModel::OnDoneClicked() {
+ dismissal_reason_ = metrics_util::CLICKED_DONE;
+}
+
+// TODO(gcasto): Is it worth having this be separate from OnDoneClicked()?
+// User intent is pretty similar in both cases.
+void ManagePasswordsBubbleModel::OnOKClicked() {
+ dismissal_reason_ = metrics_util::CLICKED_OK;
}
void ManagePasswordsBubbleModel::OnManageLinkClicked() {
- chrome::ShowSettingsSubPage(chrome::FindBrowserWithWebContents(web_contents_),
- chrome::kPasswordManagerSubPage);
+ dismissal_reason_ = metrics_util::CLICKED_MANAGE;
+ ManagePasswordsUIController::FromWebContents(web_contents())
+ ->NavigateToPasswordManagerSettingsPage();
+}
+
+// TODO(gcasto): Is it worth having a new dismissal reason to distinguish
+// the two management cases? User intention is pretty similar between the two,
+// but the context in which they are shown is pretty different since one is
+// from an explict action and the other isn't.
+void ManagePasswordsBubbleModel::OnRemoteManageLinkClicked() {
+ dismissal_reason_ = metrics_util::CLICKED_MANAGE;
+ ManagePasswordsUIController::FromWebContents(web_contents())
+ ->NavigateToAccountCentralManagementPage();
}
void ManagePasswordsBubbleModel::OnPasswordAction(
- autofill::PasswordForm password_form,
- bool remove) {
- if (!web_contents_)
+ const autofill::PasswordForm& password_form,
+ PasswordAction action) {
+ if (!web_contents())
return;
Profile* profile =
- Profile::FromBrowserContext(web_contents_->GetBrowserContext());
- PasswordStore* password_store = PasswordStoreFactory::GetForProfile(
- profile, Profile::EXPLICIT_ACCESS).get();
+ Profile::FromBrowserContext(web_contents()->GetBrowserContext());
+ password_manager::PasswordStore* password_store =
+ PasswordStoreFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS)
+ .get();
DCHECK(password_store);
- if (remove)
+ if (action == REMOVE_PASSWORD)
password_store->RemoveLogin(password_form);
else
password_store->AddLogin(password_form);
- // This is necessary in case the bubble is instantiated again, we thus do not
- // display the pending credentials if they were deleted.
- if (password_form.username_value == pending_credentials_.username_value) {
- ManagePasswordsBubbleUIController::FromWebContents(web_contents_)->
- set_password_submitted(!remove);
- }
-}
-
-void ManagePasswordsBubbleModel::DeleteFromBestMatches(
- autofill::PasswordForm password_form) {
- ManagePasswordsBubbleUIController::FromWebContents(web_contents_)->
- RemoveFromBestMatches(password_form);
-}
-
-void ManagePasswordsBubbleModel::WebContentsDestroyed(
- content::WebContents* web_contents) {
- // The WebContents have been destroyed.
- web_contents_ = NULL;
}