Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / ui / passwords / manage_passwords_ui_controller.cc
blob5fcb462b175919882c5024cb4c6f74fe0e4b607e
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.
5 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
7 #include "base/auto_reset.h"
8 #include "chrome/app/chrome_command_ids.h"
9 #include "chrome/browser/browsing_data/browsing_data_helper.h"
10 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
11 #include "chrome/browser/password_manager/password_store_factory.h"
12 #include "chrome/browser/ui/browser_command_controller.h"
13 #include "chrome/browser/ui/browser_finder.h"
14 #include "chrome/browser/ui/browser_window.h"
15 #include "chrome/browser/ui/chrome_pages.h"
16 #include "chrome/browser/ui/location_bar/location_bar.h"
17 #include "chrome/browser/ui/passwords/manage_passwords_icon.h"
18 #include "chrome/browser/ui/passwords/password_bubble_experiment.h"
19 #include "chrome/browser/ui/tab_dialogs.h"
20 #include "chrome/common/url_constants.h"
21 #include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
22 #include "components/password_manager/core/browser/password_form_manager.h"
23 #include "components/password_manager/core/common/credential_manager_types.h"
24 #include "content/public/browser/navigation_details.h"
26 #if defined(OS_ANDROID)
27 #include "chrome/browser/android/chromium_application.h"
28 #include "chrome/browser/infobars/infobar_service.h"
29 #include "chrome/browser/password_manager/account_chooser_infobar_delegate_android.h"
30 #endif
32 using autofill::PasswordFormMap;
33 using password_manager::PasswordFormManager;
35 namespace {
37 password_manager::PasswordStore* GetPasswordStore(
38 content::WebContents* web_contents) {
39 return PasswordStoreFactory::GetForProfile(
40 Profile::FromBrowserContext(web_contents->GetBrowserContext()),
41 ServiceAccessType::EXPLICIT_ACCESS).get();
44 } // namespace
46 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ManagePasswordsUIController);
48 ManagePasswordsUIController::ManagePasswordsUIController(
49 content::WebContents* web_contents)
50 : content::WebContentsObserver(web_contents),
51 should_pop_up_bubble_(false) {
52 passwords_data_.set_client(
53 ChromePasswordManagerClient::FromWebContents(web_contents));
54 password_manager::PasswordStore* password_store =
55 GetPasswordStore(web_contents);
56 if (password_store)
57 password_store->AddObserver(this);
60 ManagePasswordsUIController::~ManagePasswordsUIController() {}
62 void ManagePasswordsUIController::UpdateBubbleAndIconVisibility() {
63 // If we're not on a "webby" URL (e.g. "chrome://sign-in"), we shouldn't
64 // display either the bubble or the icon.
65 if (!BrowsingDataHelper::IsWebScheme(
66 web_contents()->GetLastCommittedURL().scheme())) {
67 passwords_data_.OnInactive();
70 #if !defined(OS_ANDROID)
71 Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
72 if (!browser)
73 return;
74 LocationBar* location_bar = browser->window()->GetLocationBar();
75 DCHECK(location_bar);
76 location_bar->UpdateManagePasswordsIconAndBubble();
77 #endif
80 void ManagePasswordsUIController::
81 UpdateAndroidAccountChooserInfoBarVisibility() {
82 #if defined(OS_ANDROID)
83 AccountChooserInfoBarDelegateAndroid::Create(
84 InfoBarService::FromWebContents(web_contents()), this);
85 should_pop_up_bubble_ = false;
86 #endif
89 base::TimeDelta ManagePasswordsUIController::Elapsed() const {
90 return timer_ ? timer_->Elapsed() : base::TimeDelta::Max();
93 void ManagePasswordsUIController::OnPasswordSubmitted(
94 scoped_ptr<PasswordFormManager> form_manager) {
95 passwords_data_.OnPendingPassword(form_manager.Pass());
96 timer_.reset(new base::ElapsedTimer);
97 base::AutoReset<bool> resetter(&should_pop_up_bubble_, true);
98 UpdateBubbleAndIconVisibility();
101 bool ManagePasswordsUIController::OnChooseCredentials(
102 ScopedVector<autofill::PasswordForm> local_credentials,
103 ScopedVector<autofill::PasswordForm> federated_credentials,
104 const GURL& origin,
105 base::Callback<void(const password_manager::CredentialInfo&)> callback) {
106 DCHECK_IMPLIES(local_credentials.empty(), !federated_credentials.empty());
107 passwords_data_.OnRequestCredentials(local_credentials.Pass(),
108 federated_credentials.Pass(),
109 origin);
110 base::AutoReset<bool> resetter(&should_pop_up_bubble_, true);
111 #if defined(OS_ANDROID)
112 UpdateAndroidAccountChooserInfoBarVisibility();
113 #else
114 UpdateBubbleAndIconVisibility();
115 #endif
116 if (!should_pop_up_bubble_) {
117 passwords_data_.set_credentials_callback(callback);
118 return true;
120 passwords_data_.TransitionToState(password_manager::ui::MANAGE_STATE);
121 return false;
124 void ManagePasswordsUIController::OnAutoSignin(
125 ScopedVector<autofill::PasswordForm> local_forms) {
126 DCHECK(!local_forms.empty());
127 passwords_data_.OnAutoSignin(local_forms.Pass());
128 timer_.reset(new base::ElapsedTimer);
129 base::AutoReset<bool> resetter(&should_pop_up_bubble_, true);
130 UpdateBubbleAndIconVisibility();
133 void ManagePasswordsUIController::OnAutomaticPasswordSave(
134 scoped_ptr<PasswordFormManager> form_manager) {
135 passwords_data_.OnAutomaticPasswordSave(form_manager.Pass());
136 base::AutoReset<bool> resetter(&should_pop_up_bubble_, true);
137 UpdateBubbleAndIconVisibility();
140 void ManagePasswordsUIController::OnPasswordAutofilled(
141 const PasswordFormMap& password_form_map) {
142 passwords_data_.OnPasswordAutofilled(password_form_map);
143 UpdateBubbleAndIconVisibility();
146 void ManagePasswordsUIController::OnBlacklistBlockedAutofill(
147 const PasswordFormMap& password_form_map) {
148 passwords_data_.OnBlacklistBlockedAutofill(password_form_map);
149 UpdateBubbleAndIconVisibility();
152 void ManagePasswordsUIController::OnLoginsChanged(
153 const password_manager::PasswordStoreChangeList& changes) {
154 password_manager::ui::State current_state = state();
155 passwords_data_.ProcessLoginsChanged(changes);
156 if (current_state != state())
157 UpdateBubbleAndIconVisibility();
160 void ManagePasswordsUIController::
161 NavigateToPasswordManagerSettingsPage() {
162 #if defined(OS_ANDROID)
163 chrome::android::ChromiumApplication::ShowPasswordSettings();
164 #else
165 chrome::ShowSettingsSubPage(
166 chrome::FindBrowserWithWebContents(web_contents()),
167 chrome::kPasswordManagerSubPage);
168 #endif
171 void ManagePasswordsUIController::SavePassword() {
172 DCHECK(PasswordPendingUserDecision());
173 SavePasswordInternal();
174 passwords_data_.TransitionToState(password_manager::ui::MANAGE_STATE);
175 UpdateBubbleAndIconVisibility();
178 void ManagePasswordsUIController::ChooseCredential(
179 const autofill::PasswordForm& form,
180 password_manager::CredentialType credential_type) {
181 DCHECK_EQ(password_manager::ui::CREDENTIAL_REQUEST_STATE, state());
182 DCHECK(!passwords_data_.credentials_callback().is_null());
184 // Here, |credential_type| refers to whether the credential was originally
185 // passed into ::OnChooseCredentials as part of the |local_credentials| or
186 // |federated_credentials| lists (e.g. whether it is an existing credential
187 // saved for this origin, or whether we should synthesize a new
188 // FederatedCredential).
190 // If |credential_type| is federated, the credential MUST be returned as
191 // a FederatedCredential in order to prevent password information leaking
192 // cross-origin.
194 // If |credential_type| is local, the credential MIGHT be a LocalCredential
195 // or it MIGHT be a FederatedCredential. We inspect the |federation_url|
196 // field to determine which we should return.
198 // TODO(mkwst): Clean this up. It is confusing.
199 password_manager::CredentialType type_to_return;
200 if (credential_type ==
201 password_manager::CredentialType::CREDENTIAL_TYPE_LOCAL &&
202 form.federation_url.is_empty()) {
203 type_to_return = password_manager::CredentialType::CREDENTIAL_TYPE_LOCAL;
204 } else if (credential_type ==
205 password_manager::CredentialType::CREDENTIAL_TYPE_EMPTY) {
206 type_to_return = password_manager::CredentialType::CREDENTIAL_TYPE_EMPTY;
207 } else {
208 type_to_return =
209 password_manager::CredentialType::CREDENTIAL_TYPE_FEDERATED;
211 password_manager::CredentialInfo info =
212 password_manager::CredentialInfo(form, type_to_return);
213 passwords_data_.credentials_callback().Run(info);
214 passwords_data_.set_credentials_callback(
215 ManagePasswordsState::CredentialsCallback());
218 void ManagePasswordsUIController::SavePasswordInternal() {
219 password_manager::PasswordFormManager* form_manager =
220 passwords_data_.form_manager();
221 // TODO(vasilii): it's not OK to call SavePassword() when |form_manager| is 0.
222 // If this is a cause of http://crbug.com/468474 then we should hide the
223 // bubble when ManagePasswordsUIController changes its internal state.
224 if (form_manager)
225 form_manager->Save();
228 void ManagePasswordsUIController::NeverSavePassword() {
229 DCHECK(PasswordPendingUserDecision());
230 NeverSavePasswordInternal();
231 passwords_data_.TransitionToState(password_manager::ui::BLACKLIST_STATE);
232 UpdateBubbleAndIconVisibility();
235 void ManagePasswordsUIController::NeverSavePasswordInternal() {
236 password_manager::PasswordFormManager* form_manager =
237 passwords_data_.form_manager();
238 DCHECK(form_manager);
239 form_manager->PermanentlyBlacklist();
242 void ManagePasswordsUIController::UnblacklistSite() {
243 // We're in one of two states: either the user _just_ blacklisted the site
244 // by clicking "Never save" in the pending bubble, or the user is visiting
245 // a blacklisted site.
247 // Either way, |passwords_data_| has been populated with the relevant form. We
248 // can safely pull it out, send it over to the password store for removal, and
249 // update our internal state.
250 DCHECK(!passwords_data_.GetCurrentForms().empty());
251 DCHECK_EQ(password_manager::ui::BLACKLIST_STATE, state());
252 password_manager::PasswordStore* password_store =
253 GetPasswordStore(web_contents());
254 DCHECK(GetCurrentForms().front()->blacklisted_by_user);
255 if (password_store)
256 password_store->RemoveLogin(*GetCurrentForms().front());
257 passwords_data_.TransitionToState(password_manager::ui::MANAGE_STATE);
258 UpdateBubbleAndIconVisibility();
261 void ManagePasswordsUIController::ManageAccounts() {
262 DCHECK_EQ(password_manager::ui::AUTO_SIGNIN_STATE, state());
263 passwords_data_.TransitionToState(password_manager::ui::MANAGE_STATE);
264 base::AutoReset<bool> resetter(&should_pop_up_bubble_, true);
265 UpdateBubbleAndIconVisibility();
268 void ManagePasswordsUIController::DidNavigateMainFrame(
269 const content::LoadCommittedDetails& details,
270 const content::FrameNavigateParams& params) {
271 // Don't react to in-page (fragment) navigations.
272 if (details.is_in_page)
273 return;
275 // Don't do anything if a navigation occurs before a user could reasonably
276 // interact with the password bubble.
277 if (Elapsed() < base::TimeDelta::FromSeconds(1))
278 return;
280 // Otherwise, reset the password manager and the timer.
281 passwords_data_.OnInactive();
282 UpdateBubbleAndIconVisibility();
283 // This allows the bubble to survive several redirects in case the whole
284 // process of navigating to the landing page is longer than 1 second.
285 timer_.reset(new base::ElapsedTimer());
288 void ManagePasswordsUIController::WasHidden() {
289 #if !defined(OS_ANDROID)
290 TabDialogs::FromWebContents(web_contents())->HideManagePasswordsBubble();
291 #endif
294 const autofill::PasswordForm& ManagePasswordsUIController::
295 PendingPassword() const {
296 DCHECK(state() == password_manager::ui::PENDING_PASSWORD_STATE ||
297 state() == password_manager::ui::CONFIRMATION_STATE) << state();
298 password_manager::PasswordFormManager* form_manager =
299 passwords_data_.form_manager();
300 DCHECK(form_manager);
301 return form_manager->pending_credentials();
304 void ManagePasswordsUIController::UpdateIconAndBubbleState(
305 ManagePasswordsIcon* icon) {
306 if (should_pop_up_bubble_) {
307 // We must display the icon before showing the bubble, as the bubble would
308 // be otherwise unanchored.
309 icon->SetState(state());
310 ShowBubbleWithoutUserInteraction();
311 } else {
312 icon->SetState(state());
316 void ManagePasswordsUIController::OnBubbleShown() {
317 should_pop_up_bubble_ = false;
320 void ManagePasswordsUIController::OnBubbleHidden() {
321 if (state() == password_manager::ui::CREDENTIAL_REQUEST_STATE ||
322 state() == password_manager::ui::CONFIRMATION_STATE ||
323 state() == password_manager::ui::AUTO_SIGNIN_STATE) {
324 passwords_data_.TransitionToState(password_manager::ui::MANAGE_STATE);
325 UpdateBubbleAndIconVisibility();
329 void ManagePasswordsUIController::ShowBubbleWithoutUserInteraction() {
330 DCHECK(should_pop_up_bubble_);
331 #if !defined(OS_ANDROID)
332 Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
333 if (!browser || browser->toolbar_model()->input_in_progress())
334 return;
336 CommandUpdater* updater = browser->command_controller()->command_updater();
337 updater->ExecuteCommand(IDC_MANAGE_PASSWORDS_FOR_PAGE);
338 #endif
341 void ManagePasswordsUIController::WebContentsDestroyed() {
342 password_manager::PasswordStore* password_store =
343 GetPasswordStore(web_contents());
344 if (password_store)
345 password_store->RemoveObserver(this);