[Extensions] Cleanup Extension Uninstall Dialog logic
[chromium-blink-merge.git] / chrome / browser / ui / passwords / manage_passwords_bubble_model.cc
blobaf537be63d2e730cf5bcdfe686090f0b2a2c9a90
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
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
7 #include "base/command_line.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/password_manager/password_store_factory.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/signin/signin_manager_factory.h"
12 #include "chrome/browser/sync/profile_sync_service.h"
13 #include "chrome/browser/sync/profile_sync_service_factory.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/browser_finder.h"
16 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
17 #include "chrome/common/url_constants.h"
18 #include "chrome/grit/chromium_strings.h"
19 #include "chrome/grit/generated_resources.h"
20 #include "components/feedback/feedback_data.h"
21 #include "components/feedback/feedback_util.h"
22 #include "components/password_manager/core/browser/password_bubble_experiment.h"
23 #include "components/password_manager/core/browser/password_store.h"
24 #include "components/password_manager/core/common/credential_manager_types.h"
25 #include "components/password_manager/core/common/password_manager_ui.h"
26 #include "components/signin/core/browser/signin_manager.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/common/content_switches.h"
29 #include "ui/base/l10n/l10n_util.h"
30 #include "ui/base/resource/resource_bundle.h"
32 using autofill::PasswordFormMap;
33 using feedback::FeedbackData;
34 using content::WebContents;
35 namespace metrics_util = password_manager::metrics_util;
37 namespace {
39 enum FieldType { USERNAME_FIELD, PASSWORD_FIELD };
41 const int kUsernameFieldSize = 30;
42 const int kPasswordFieldSize = 22;
44 // Returns the width of |type| field.
45 int GetFieldWidth(FieldType type) {
46 return ui::ResourceBundle::GetSharedInstance()
47 .GetFontList(ui::ResourceBundle::SmallFont)
48 .GetExpectedTextWidth(type == USERNAME_FIELD ? kUsernameFieldSize
49 : kPasswordFieldSize);
52 Profile* GetProfileFromWebContents(content::WebContents* web_contents) {
53 if (!web_contents)
54 return nullptr;
55 return Profile::FromBrowserContext(web_contents->GetBrowserContext());
58 void RecordExperimentStatistics(content::WebContents* web_contents,
59 metrics_util::UIDismissalReason reason) {
60 Profile* profile = GetProfileFromWebContents(web_contents);
61 if (!profile)
62 return;
63 password_bubble_experiment::RecordBubbleClosed(profile->GetPrefs(), reason);
66 ScopedVector<const autofill::PasswordForm> DeepCopyForms(
67 const std::vector<const autofill::PasswordForm*>& forms) {
68 ScopedVector<const autofill::PasswordForm> result;
69 result.reserve(forms.size());
70 std::transform(forms.begin(), forms.end(), std::back_inserter(result),
71 [](const autofill::PasswordForm* form) {
72 return new autofill::PasswordForm(*form);
73 });
74 return result.Pass();
77 // A wrapper around password_bubble_experiment::IsSmartLockBrandingEnabled
78 // extracting the sync_service from the profile.
79 bool IsSmartLockBrandingEnabled(Profile* profile) {
80 const ProfileSyncService* sync_service =
81 ProfileSyncServiceFactory::GetForProfile(profile);
82 return password_bubble_experiment::IsSmartLockBrandingEnabled(sync_service);
85 } // namespace
87 ManagePasswordsBubbleModel::ManagePasswordsBubbleModel(
88 content::WebContents* web_contents)
89 : content::WebContentsObserver(web_contents),
90 never_save_passwords_(false),
91 display_disposition_(metrics_util::AUTOMATIC_WITH_PASSWORD_PENDING),
92 dismissal_reason_(metrics_util::NOT_DISPLAYED) {
93 ManagePasswordsUIController* controller =
94 ManagePasswordsUIController::FromWebContents(web_contents);
96 origin_ = controller->origin();
97 state_ = controller->state();
98 if (state_ == password_manager::ui::PENDING_PASSWORD_STATE) {
99 pending_password_ = controller->PendingPassword();
100 local_credentials_ = DeepCopyForms(controller->GetCurrentForms());
101 } else if (state_ == password_manager::ui::CONFIRMATION_STATE) {
102 // We don't need anything.
103 } else if (state_ == password_manager::ui::CREDENTIAL_REQUEST_STATE) {
104 local_credentials_ = DeepCopyForms(controller->GetCurrentForms());
105 federated_credentials_ = DeepCopyForms(controller->GetFederatedForms());
106 } else if (state_ == password_manager::ui::AUTO_SIGNIN_STATE) {
107 pending_password_ = *controller->GetCurrentForms()[0];
108 } else {
109 local_credentials_ = DeepCopyForms(controller->GetCurrentForms());
112 if (state_ == password_manager::ui::PENDING_PASSWORD_STATE) {
113 UpdatePendingStateTitle();
114 } else if (state_ == password_manager::ui::BLACKLIST_STATE) {
115 title_ = l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_BLACKLISTED_TITLE);
116 } else if (state_ == password_manager::ui::CONFIRMATION_STATE) {
117 title_ =
118 l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TITLE);
119 } else if (state_ == password_manager::ui::CREDENTIAL_REQUEST_STATE) {
120 title_ = l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_CHOOSE_TITLE);
121 } else if (state_ == password_manager::ui::AUTO_SIGNIN_STATE) {
122 // There is no title.
123 } else {
124 title_ = IsNewUIActive() ?
125 l10n_util::GetStringFUTF16(IDS_MANAGE_ACCOUNTS_TITLE,
126 base::UTF8ToUTF16(origin_.spec())) :
127 l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_TITLE);
130 if (state_ == password_manager::ui::CONFIRMATION_STATE) {
131 base::string16 save_confirmation_link =
132 l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_LINK);
133 int confirmation_text_id = IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TEXT;
134 if (IsSmartLockBrandingEnabled(GetProfile())) {
135 std::string management_hostname =
136 GURL(chrome::kPasswordManagerAccountDashboardURL).host();
137 save_confirmation_link = base::UTF8ToUTF16(management_hostname);
138 confirmation_text_id =
139 IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_SMART_LOCK_TEXT;
142 size_t offset;
143 save_confirmation_text_ =
144 l10n_util::GetStringFUTF16(
145 confirmation_text_id, save_confirmation_link, &offset);
146 save_confirmation_link_range_ =
147 gfx::Range(offset, offset + save_confirmation_link.length());
150 manage_link_ =
151 l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_MANAGE_PASSWORDS_LINK);
154 ManagePasswordsBubbleModel::~ManagePasswordsBubbleModel() {}
156 void ManagePasswordsBubbleModel::OnBubbleShown(
157 ManagePasswordsBubble::DisplayReason reason) {
158 if (reason == ManagePasswordsBubble::USER_ACTION) {
159 if (state_ == password_manager::ui::PENDING_PASSWORD_STATE) {
160 display_disposition_ = metrics_util::MANUAL_WITH_PASSWORD_PENDING;
161 } else if (state_ == password_manager::ui::BLACKLIST_STATE) {
162 display_disposition_ = metrics_util::MANUAL_BLACKLISTED;
163 } else {
164 display_disposition_ = metrics_util::MANUAL_MANAGE_PASSWORDS;
166 } else {
167 if (state_ == password_manager::ui::CONFIRMATION_STATE) {
168 display_disposition_ =
169 metrics_util::AUTOMATIC_GENERATED_PASSWORD_CONFIRMATION;
170 } else if (state_ == password_manager::ui::CREDENTIAL_REQUEST_STATE) {
171 display_disposition_ = metrics_util::AUTOMATIC_CREDENTIAL_REQUEST;
172 } else if (state_ == password_manager::ui::AUTO_SIGNIN_STATE) {
173 display_disposition_ = metrics_util::AUTOMATIC_SIGNIN_TOAST;
174 } else {
175 display_disposition_ = metrics_util::AUTOMATIC_WITH_PASSWORD_PENDING;
178 metrics_util::LogUIDisplayDisposition(display_disposition_);
180 // Default to a dismissal reason of "no interaction". If the user interacts
181 // with the button in such a way that it closes, we'll reset this value
182 // accordingly.
183 dismissal_reason_ = metrics_util::NO_DIRECT_INTERACTION;
185 ManagePasswordsUIController* controller =
186 ManagePasswordsUIController::FromWebContents(web_contents());
187 controller->OnBubbleShown();
190 void ManagePasswordsBubbleModel::OnBubbleHidden() {
191 ManagePasswordsUIController* manage_passwords_ui_controller =
192 web_contents() ?
193 ManagePasswordsUIController::FromWebContents(web_contents())
194 : nullptr;
195 if (manage_passwords_ui_controller)
196 manage_passwords_ui_controller->OnBubbleHidden();
197 if (dismissal_reason_ == metrics_util::NOT_DISPLAYED)
198 return;
200 metrics_util::LogUIDismissalReason(dismissal_reason_);
201 // Other use cases have been reported in the callbacks like OnSaveClicked().
202 if (state_ == password_manager::ui::PENDING_PASSWORD_STATE &&
203 dismissal_reason_ == metrics_util::NO_DIRECT_INTERACTION)
204 RecordExperimentStatistics(web_contents(), dismissal_reason_);
207 void ManagePasswordsBubbleModel::OnNopeClicked() {
208 dismissal_reason_ = metrics_util::CLICKED_NOPE;
209 RecordExperimentStatistics(web_contents(), dismissal_reason_);
210 if (state_ != password_manager::ui::CREDENTIAL_REQUEST_STATE)
211 state_ = password_manager::ui::PENDING_PASSWORD_STATE;
214 void ManagePasswordsBubbleModel::OnConfirmationForNeverForThisSite() {
215 never_save_passwords_ = true;
216 UpdatePendingStateTitle();
219 void ManagePasswordsBubbleModel::OnUndoNeverForThisSite() {
220 never_save_passwords_ = false;
221 UpdatePendingStateTitle();
224 void ManagePasswordsBubbleModel::OnNeverForThisSiteClicked() {
225 dismissal_reason_ = metrics_util::CLICKED_NEVER;
226 RecordExperimentStatistics(web_contents(), dismissal_reason_);
227 ManagePasswordsUIController* manage_passwords_ui_controller =
228 ManagePasswordsUIController::FromWebContents(web_contents());
229 manage_passwords_ui_controller->NeverSavePassword();
230 state_ = password_manager::ui::BLACKLIST_STATE;
233 void ManagePasswordsBubbleModel::OnUnblacklistClicked() {
234 dismissal_reason_ = metrics_util::CLICKED_UNBLACKLIST;
235 ManagePasswordsUIController* manage_passwords_ui_controller =
236 ManagePasswordsUIController::FromWebContents(web_contents());
237 manage_passwords_ui_controller->UnblacklistSite();
238 state_ = password_manager::ui::MANAGE_STATE;
241 void ManagePasswordsBubbleModel::OnSaveClicked() {
242 dismissal_reason_ = metrics_util::CLICKED_SAVE;
243 RecordExperimentStatistics(web_contents(), dismissal_reason_);
244 ManagePasswordsUIController* manage_passwords_ui_controller =
245 ManagePasswordsUIController::FromWebContents(web_contents());
246 manage_passwords_ui_controller->SavePassword();
247 state_ = password_manager::ui::MANAGE_STATE;
250 void ManagePasswordsBubbleModel::OnDoneClicked() {
251 dismissal_reason_ = metrics_util::CLICKED_DONE;
254 // TODO(gcasto): Is it worth having this be separate from OnDoneClicked()?
255 // User intent is pretty similar in both cases.
256 void ManagePasswordsBubbleModel::OnOKClicked() {
257 dismissal_reason_ = metrics_util::CLICKED_OK;
260 void ManagePasswordsBubbleModel::OnManageLinkClicked() {
261 dismissal_reason_ = metrics_util::CLICKED_MANAGE;
262 if (IsSmartLockBrandingEnabled(GetProfile())) {
263 ManagePasswordsUIController::FromWebContents(web_contents())
264 ->NavigateToExternalPasswordManager();
265 } else {
266 ManagePasswordsUIController::FromWebContents(web_contents())
267 ->NavigateToPasswordManagerSettingsPage();
271 void ManagePasswordsBubbleModel::OnBrandLinkClicked() {
272 dismissal_reason_ = metrics_util::CLICKED_BRAND_NAME;
273 ManagePasswordsUIController::FromWebContents(web_contents())
274 ->NavigateToSmartLockHelpArticle();
277 void ManagePasswordsBubbleModel::OnAutoSignInToastTimeout() {
278 dismissal_reason_ = metrics_util::AUTO_SIGNIN_TOAST_TIMEOUT;
281 void ManagePasswordsBubbleModel::OnAutoSignInClicked() {
282 dismissal_reason_ = metrics_util::AUTO_SIGNIN_TOAST_CLICKED;
283 ManagePasswordsUIController* manage_passwords_ui_controller =
284 ManagePasswordsUIController::FromWebContents(web_contents());
285 manage_passwords_ui_controller->ManageAccounts();
286 state_ = password_manager::ui::MANAGE_STATE;
289 void ManagePasswordsBubbleModel::OnPasswordAction(
290 const autofill::PasswordForm& password_form,
291 PasswordAction action) {
292 if (!web_contents())
293 return;
294 Profile* profile =
295 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
296 password_manager::PasswordStore* password_store =
297 PasswordStoreFactory::GetForProfile(
298 profile, ServiceAccessType::EXPLICIT_ACCESS).get();
299 DCHECK(password_store);
300 if (action == REMOVE_PASSWORD)
301 password_store->RemoveLogin(password_form);
302 else
303 password_store->AddLogin(password_form);
306 void ManagePasswordsBubbleModel::OnChooseCredentials(
307 const autofill::PasswordForm& password_form,
308 password_manager::CredentialType credential_type) {
309 dismissal_reason_ = metrics_util::CLICKED_CREDENTIAL;
310 ManagePasswordsUIController* manage_passwords_ui_controller =
311 ManagePasswordsUIController::FromWebContents(web_contents());
312 manage_passwords_ui_controller->ChooseCredential(password_form,
313 credential_type);
314 state_ = password_manager::ui::INACTIVE_STATE;
317 Profile* ManagePasswordsBubbleModel::GetProfile() const {
318 return GetProfileFromWebContents(web_contents());
321 bool ManagePasswordsBubbleModel::IsNewUIActive() const {
322 return base::CommandLine::ForCurrentProcess()->HasSwitch(
323 switches::kEnableCredentialManagerAPI);
326 // static
327 int ManagePasswordsBubbleModel::UsernameFieldWidth() {
328 return GetFieldWidth(USERNAME_FIELD);
331 // static
332 int ManagePasswordsBubbleModel::PasswordFieldWidth() {
333 return GetFieldWidth(PASSWORD_FIELD);
336 void ManagePasswordsBubbleModel::UpdatePendingStateTitle() {
337 title_brand_link_range_ = gfx::Range();
338 if (never_save_passwords_) {
339 title_ = l10n_util::GetStringUTF16(
340 IDS_MANAGE_PASSWORDS_BLACKLIST_CONFIRMATION_TITLE);
341 } else if (IsSmartLockBrandingEnabled(GetProfile())) {
342 // "Google Smart Lock" should be a hyperlink.
343 base::string16 brand_link =
344 l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SMART_LOCK);
345 size_t offset = 0;
346 title_ = l10n_util::GetStringFUTF16(IDS_SAVE_PASSWORD, brand_link, &offset);
347 title_brand_link_range_ = gfx::Range(offset, offset + brand_link.length());
348 } else {
349 base::string16 brand_link =
350 l10n_util::GetStringUTF16(IDS_SAVE_PASSWORD_TITLE_BRAND);
351 title_ = l10n_util::GetStringFUTF16(IDS_SAVE_PASSWORD, brand_link);