ExtensionSyncService: listen for relevant changes instead of being explicitly called...
[chromium-blink-merge.git] / chrome / browser / ui / autofill / password_generation_popup_controller_impl.cc
blob935a33875e6729157c7f7504552b7650da961b45
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/autofill/password_generation_popup_controller_impl.h"
7 #include <math.h>
9 #include "base/i18n/rtl.h"
10 #include "base/strings/string_split.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversion_utils.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/sync/profile_sync_service.h"
16 #include "chrome/browser/sync/profile_sync_service_factory.h"
17 #include "chrome/browser/ui/autofill/password_generation_popup_observer.h"
18 #include "chrome/browser/ui/autofill/password_generation_popup_view.h"
19 #include "chrome/browser/ui/autofill/popup_constants.h"
20 #include "chrome/browser/ui/browser_finder.h"
21 #include "chrome/browser/ui/chrome_pages.h"
22 #include "chrome/common/url_constants.h"
23 #include "chrome/grit/chromium_strings.h"
24 #include "chrome/grit/generated_resources.h"
25 #include "components/autofill/content/common/autofill_messages.h"
26 #include "components/autofill/core/browser/password_generator.h"
27 #include "components/password_manager/core/browser/password_bubble_experiment.h"
28 #include "components/password_manager/core/browser/password_manager.h"
29 #include "content/public/browser/native_web_keyboard_event.h"
30 #include "content/public/browser/render_view_host.h"
31 #include "content/public/browser/web_contents.h"
32 #include "ui/base/l10n/l10n_util.h"
33 #include "ui/events/keycodes/keyboard_codes.h"
34 #include "ui/gfx/geometry/rect_conversions.h"
35 #include "ui/gfx/text_utils.h"
37 #if defined(OS_ANDROID)
38 #include "chrome/browser/android/chrome_application.h"
39 #endif
41 namespace autofill {
43 base::WeakPtr<PasswordGenerationPopupControllerImpl>
44 PasswordGenerationPopupControllerImpl::GetOrCreate(
45 base::WeakPtr<PasswordGenerationPopupControllerImpl> previous,
46 const gfx::RectF& bounds,
47 const PasswordForm& form,
48 int max_length,
49 password_manager::PasswordManager* password_manager,
50 password_manager::PasswordManagerDriver* driver,
51 PasswordGenerationPopupObserver* observer,
52 content::WebContents* web_contents,
53 gfx::NativeView container_view) {
54 if (previous.get() &&
55 previous->element_bounds() == bounds &&
56 previous->web_contents() == web_contents &&
57 previous->container_view() == container_view) {
58 return previous;
61 if (previous.get())
62 previous->Hide();
64 PasswordGenerationPopupControllerImpl* controller =
65 new PasswordGenerationPopupControllerImpl(
66 bounds, form, max_length, password_manager, driver, observer,
67 web_contents, container_view);
68 return controller->GetWeakPtr();
71 PasswordGenerationPopupControllerImpl::PasswordGenerationPopupControllerImpl(
72 const gfx::RectF& bounds,
73 const PasswordForm& form,
74 int max_length,
75 password_manager::PasswordManager* password_manager,
76 password_manager::PasswordManagerDriver* driver,
77 PasswordGenerationPopupObserver* observer,
78 content::WebContents* web_contents,
79 gfx::NativeView container_view)
80 : view_(NULL),
81 form_(form),
82 password_manager_(password_manager),
83 driver_(driver),
84 observer_(observer),
85 generator_(new PasswordGenerator(max_length)),
86 // TODO(estade): use correct text direction.
87 controller_common_(bounds,
88 base::i18n::LEFT_TO_RIGHT,
89 container_view,
90 web_contents),
91 password_selected_(false),
92 display_password_(false),
93 weak_ptr_factory_(this) {
94 controller_common_.SetKeyPressCallback(
95 base::Bind(&PasswordGenerationPopupControllerImpl::HandleKeyPressEvent,
96 base::Unretained(this)));
98 int link_id = IDS_MANAGE_PASSWORDS_LINK;
99 int help_text_id = IDS_PASSWORD_GENERATION_PROMPT;
100 const ProfileSyncService* sync_service =
101 ProfileSyncServiceFactory::GetForProfile(
102 Profile::FromBrowserContext(web_contents->GetBrowserContext()));
103 if (password_bubble_experiment::IsSmartLockBrandingEnabled(sync_service)) {
104 help_text_id = IDS_PASSWORD_GENERATION_SMART_LOCK_PROMPT;
105 link_id = IDS_PASSWORD_MANAGER_SMART_LOCK_FOR_PASSWORDS;
108 base::string16 link = l10n_util::GetStringUTF16(link_id);
109 size_t offset;
110 help_text_ = l10n_util::GetStringFUTF16(help_text_id, link, &offset);
111 link_range_ = gfx::Range(offset, offset + link.length());
114 PasswordGenerationPopupControllerImpl::~PasswordGenerationPopupControllerImpl()
117 base::WeakPtr<PasswordGenerationPopupControllerImpl>
118 PasswordGenerationPopupControllerImpl::GetWeakPtr() {
119 return weak_ptr_factory_.GetWeakPtr();
122 bool PasswordGenerationPopupControllerImpl::HandleKeyPressEvent(
123 const content::NativeWebKeyboardEvent& event) {
124 switch (event.windowsKeyCode) {
125 case ui::VKEY_UP:
126 case ui::VKEY_DOWN:
127 PasswordSelected(true);
128 return true;
129 case ui::VKEY_ESCAPE:
130 Hide();
131 return true;
132 case ui::VKEY_RETURN:
133 case ui::VKEY_TAB:
134 // We suppress tab if the password is selected because we will
135 // automatically advance focus anyway.
136 return PossiblyAcceptPassword();
137 default:
138 return false;
142 bool PasswordGenerationPopupControllerImpl::PossiblyAcceptPassword() {
143 if (password_selected_) {
144 PasswordAccepted(); // This will delete |this|.
145 return true;
148 return false;
151 void PasswordGenerationPopupControllerImpl::PasswordSelected(bool selected) {
152 if (!display_password_ || selected == password_selected_)
153 return;
155 password_selected_ = selected;
156 view_->PasswordSelectionUpdated();
157 view_->UpdateBoundsAndRedrawPopup();
160 void PasswordGenerationPopupControllerImpl::PasswordAccepted() {
161 if (!display_password_)
162 return;
164 driver_->GeneratedPasswordAccepted(current_password_);
165 password_manager_->SetHasGeneratedPasswordForForm(driver_, form_, true);
166 Hide();
169 int PasswordGenerationPopupControllerImpl::GetMinimumWidth() {
170 // Minimum width in pixels.
171 const int minimum_width = 350;
173 // If the width of the field is longer than the minimum, use that instead.
174 return std::max(minimum_width,
175 controller_common_.RoundedElementBounds().width());
178 void PasswordGenerationPopupControllerImpl::CalculateBounds() {
179 gfx::Size bounds = view_->GetPreferredSizeOfPasswordView();
181 popup_bounds_ = controller_common_.GetPopupBounds(bounds.width(),
182 bounds.height());
185 void PasswordGenerationPopupControllerImpl::Show(bool display_password) {
186 display_password_ = display_password;
187 if (display_password_ && current_password_.empty())
188 current_password_ = base::ASCIIToUTF16(generator_->Generate());
190 if (!view_) {
191 view_ = PasswordGenerationPopupView::Create(this);
193 // Treat popup as being hidden if creation fails.
194 if (!view_) {
195 Hide();
196 return;
199 CalculateBounds();
200 view_->Show();
201 } else {
202 CalculateBounds();
203 view_->UpdateBoundsAndRedrawPopup();
206 controller_common_.RegisterKeyPressCallback();
208 if (observer_)
209 observer_->OnPopupShown(display_password_);
212 void PasswordGenerationPopupControllerImpl::HideAndDestroy() {
213 Hide();
216 void PasswordGenerationPopupControllerImpl::Hide() {
217 controller_common_.RemoveKeyPressCallback();
219 if (view_)
220 view_->Hide();
222 if (observer_)
223 observer_->OnPopupHidden();
225 delete this;
228 void PasswordGenerationPopupControllerImpl::ViewDestroyed() {
229 view_ = NULL;
231 Hide();
234 void PasswordGenerationPopupControllerImpl::OnSavedPasswordsLinkClicked() {
235 #if defined(OS_ANDROID)
236 chrome::android::ChromeApplication::ShowPasswordSettings();
237 #else
238 chrome::ShowSettingsSubPage(
239 chrome::FindBrowserWithWebContents(controller_common_.web_contents()),
240 chrome::kPasswordManagerSubPage);
241 #endif
244 void PasswordGenerationPopupControllerImpl::SetSelectionAtPoint(
245 const gfx::Point& point) {
246 PasswordSelected(view_->IsPointInPasswordBounds(point));
249 bool PasswordGenerationPopupControllerImpl::AcceptSelectedLine() {
250 if (!password_selected_)
251 return false;
253 PasswordAccepted();
254 return true;
257 void PasswordGenerationPopupControllerImpl::SelectionCleared() {
258 PasswordSelected(false);
261 gfx::NativeView PasswordGenerationPopupControllerImpl::container_view() {
262 return controller_common_.container_view();
265 const gfx::Rect& PasswordGenerationPopupControllerImpl::popup_bounds() const {
266 return popup_bounds_;
269 const gfx::RectF& PasswordGenerationPopupControllerImpl::element_bounds()
270 const {
271 return controller_common_.element_bounds();
274 bool PasswordGenerationPopupControllerImpl::IsRTL() const {
275 return base::i18n::IsRTL();
278 bool PasswordGenerationPopupControllerImpl::display_password() const {
279 return display_password_;
282 bool PasswordGenerationPopupControllerImpl::password_selected() const {
283 return password_selected_;
286 base::string16 PasswordGenerationPopupControllerImpl::password() const {
287 return current_password_;
290 base::string16 PasswordGenerationPopupControllerImpl::SuggestedText() {
291 return l10n_util::GetStringUTF16(IDS_PASSWORD_GENERATION_SUGGESTION);
294 const base::string16& PasswordGenerationPopupControllerImpl::HelpText() {
295 return help_text_;
298 const gfx::Range& PasswordGenerationPopupControllerImpl::HelpTextLinkRange() {
299 return link_range_;
302 } // namespace autofill