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"
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"
43 base::WeakPtr
<PasswordGenerationPopupControllerImpl
>
44 PasswordGenerationPopupControllerImpl::GetOrCreate(
45 base::WeakPtr
<PasswordGenerationPopupControllerImpl
> previous
,
46 const gfx::RectF
& bounds
,
47 const PasswordForm
& form
,
49 password_manager::PasswordManager
* password_manager
,
50 password_manager::PasswordManagerDriver
* driver
,
51 PasswordGenerationPopupObserver
* observer
,
52 content::WebContents
* web_contents
,
53 gfx::NativeView container_view
) {
55 previous
->element_bounds() == bounds
&&
56 previous
->web_contents() == web_contents
&&
57 previous
->container_view() == container_view
) {
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
,
75 password_manager::PasswordManager
* password_manager
,
76 password_manager::PasswordManagerDriver
* driver
,
77 PasswordGenerationPopupObserver
* observer
,
78 content::WebContents
* web_contents
,
79 gfx::NativeView container_view
)
82 password_manager_(password_manager
),
85 generator_(new PasswordGenerator(max_length
)),
86 // TODO(estade): use correct text direction.
87 controller_common_(bounds
,
88 base::i18n::LEFT_TO_RIGHT
,
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
);
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
) {
127 PasswordSelected(true);
129 case ui::VKEY_ESCAPE
:
132 case ui::VKEY_RETURN
:
134 // We suppress tab if the password is selected because we will
135 // automatically advance focus anyway.
136 return PossiblyAcceptPassword();
142 bool PasswordGenerationPopupControllerImpl::PossiblyAcceptPassword() {
143 if (password_selected_
) {
144 PasswordAccepted(); // This will delete |this|.
151 void PasswordGenerationPopupControllerImpl::PasswordSelected(bool selected
) {
152 if (!display_password_
|| selected
== password_selected_
)
155 password_selected_
= selected
;
156 view_
->PasswordSelectionUpdated();
157 view_
->UpdateBoundsAndRedrawPopup();
160 void PasswordGenerationPopupControllerImpl::PasswordAccepted() {
161 if (!display_password_
)
164 driver_
->GeneratedPasswordAccepted(current_password_
);
165 password_manager_
->SetHasGeneratedPasswordForForm(driver_
, form_
, true);
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(),
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());
191 view_
= PasswordGenerationPopupView::Create(this);
193 // Treat popup as being hidden if creation fails.
203 view_
->UpdateBoundsAndRedrawPopup();
206 controller_common_
.RegisterKeyPressCallback();
209 observer_
->OnPopupShown(display_password_
);
212 void PasswordGenerationPopupControllerImpl::HideAndDestroy() {
216 void PasswordGenerationPopupControllerImpl::Hide() {
217 controller_common_
.RemoveKeyPressCallback();
223 observer_
->OnPopupHidden();
228 void PasswordGenerationPopupControllerImpl::ViewDestroyed() {
234 void PasswordGenerationPopupControllerImpl::OnSavedPasswordsLinkClicked() {
235 #if defined(OS_ANDROID)
236 chrome::android::ChromeApplication::ShowPasswordSettings();
238 chrome::ShowSettingsSubPage(
239 chrome::FindBrowserWithWebContents(controller_common_
.web_contents()),
240 chrome::kPasswordManagerSubPage
);
244 void PasswordGenerationPopupControllerImpl::SetSelectionAtPoint(
245 const gfx::Point
& point
) {
246 PasswordSelected(view_
->IsPointInPasswordBounds(point
));
249 bool PasswordGenerationPopupControllerImpl::AcceptSelectedLine() {
250 if (!password_selected_
)
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()
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() {
298 const gfx::Range
& PasswordGenerationPopupControllerImpl::HelpTextLinkRange() {
302 } // namespace autofill