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. 4 5 #include "chrome/browser/ui/autofill/password_generation_popup_controller_impl.h" 6 7 #include <math.h> 8 9 #include "base/strings/string_split.h" 10 #include "base/strings/string_util.h" 11 #include "base/strings/utf_string_conversion_utils.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "chrome/browser/ui/autofill/password_generation_popup_observer.h" 14 #include "chrome/browser/ui/autofill/password_generation_popup_view.h" 15 #include "chrome/browser/ui/autofill/popup_constants.h" 16 #include "chrome/browser/ui/browser_finder.h" 17 #include "chrome/browser/ui/chrome_pages.h" 18 #include "chrome/common/url_constants.h" 19 #include "chrome/grit/chromium_strings.h" 20 #include "chrome/grit/generated_resources.h" 21 #include "chrome/grit/google_chrome_strings.h" 22 #include "components/autofill/content/common/autofill_messages.h" 23 #include "components/autofill/core/browser/password_generator.h" 24 #include "components/password_manager/core/browser/password_manager.h" 25 #include "content/public/browser/native_web_keyboard_event.h" 26 #include "content/public/browser/render_view_host.h" 27 #include "content/public/browser/web_contents.h" 28 #include "ui/base/l10n/l10n_util.h" 29 #include "ui/events/keycodes/keyboard_codes.h" 30 #include "ui/gfx/rect_conversions.h" 31 #include "ui/gfx/text_utils.h" 32 33 namespace autofill { 34 35 base::WeakPtr<PasswordGenerationPopupControllerImpl> 36 PasswordGenerationPopupControllerImpl::GetOrCreate( 37 base::WeakPtr<PasswordGenerationPopupControllerImpl> previous, 38 const gfx::RectF& bounds, 39 const PasswordForm& form, 40 int max_length, 41 password_manager::PasswordManager* password_manager, 42 PasswordGenerationPopupObserver* observer, 43 content::WebContents* web_contents, 44 gfx::NativeView container_view) { 45 if (previous.get() && 46 previous->element_bounds() == bounds && 47 previous->web_contents() == web_contents && 48 previous->container_view() == container_view) { 49 return previous; 50 } 51 52 if (previous.get()) 53 previous->Hide(); 54 55 PasswordGenerationPopupControllerImpl* controller = 56 new PasswordGenerationPopupControllerImpl( 57 bounds, 58 form, 59 max_length, 60 password_manager, 61 observer, 62 web_contents, 63 container_view); 64 return controller->GetWeakPtr(); 65 } 66 67 PasswordGenerationPopupControllerImpl::PasswordGenerationPopupControllerImpl( 68 const gfx::RectF& bounds, 69 const PasswordForm& form, 70 int max_length, 71 password_manager::PasswordManager* password_manager, 72 PasswordGenerationPopupObserver* observer, 73 content::WebContents* web_contents, 74 gfx::NativeView container_view) 75 : view_(NULL), 76 form_(form), 77 password_manager_(password_manager), 78 observer_(observer), 79 generator_(new PasswordGenerator(max_length)), 80 controller_common_(bounds, container_view, web_contents), 81 password_selected_(false), 82 display_password_(false), 83 weak_ptr_factory_(this) { 84 controller_common_.SetKeyPressCallback( 85 base::Bind(&PasswordGenerationPopupControllerImpl::HandleKeyPressEvent, 86 base::Unretained(this))); 87 88 std::vector<base::string16> pieces; 89 base::SplitStringDontTrim( 90 l10n_util::GetStringUTF16(IDS_PASSWORD_GENERATION_PROMPT), 91 '|', // separator 92 &pieces); 93 DCHECK_EQ(3u, pieces.size()); 94 link_range_ = gfx::Range(pieces[0].size(), 95 pieces[0].size() + pieces[1].size()); 96 help_text_ = JoinString(pieces, base::string16()); 97 } 98 99 PasswordGenerationPopupControllerImpl::~PasswordGenerationPopupControllerImpl() 100 {} 101 102 base::WeakPtr<PasswordGenerationPopupControllerImpl> 103 PasswordGenerationPopupControllerImpl::GetWeakPtr() { 104 return weak_ptr_factory_.GetWeakPtr(); 105 } 106 107 bool PasswordGenerationPopupControllerImpl::HandleKeyPressEvent( 108 const content::NativeWebKeyboardEvent& event) { 109 switch (event.windowsKeyCode) { 110 case ui::VKEY_UP: 111 case ui::VKEY_DOWN: 112 PasswordSelected(true); 113 return true; 114 case ui::VKEY_ESCAPE: 115 Hide(); 116 return true; 117 case ui::VKEY_RETURN: 118 case ui::VKEY_TAB: 119 // We suppress tab if the password is selected because we will 120 // automatically advance focus anyway. 121 return PossiblyAcceptPassword(); 122 default: 123 return false; 124 } 125 } 126 127 bool PasswordGenerationPopupControllerImpl::PossiblyAcceptPassword() { 128 if (password_selected_) { 129 PasswordAccepted(); // This will delete |this|. 130 return true; 131 } 132 133 return false; 134 } 135 136 void PasswordGenerationPopupControllerImpl::PasswordSelected(bool selected) { 137 if (!display_password_ || selected == password_selected_) 138 return; 139 140 password_selected_ = selected; 141 view_->PasswordSelectionUpdated(); 142 view_->UpdateBoundsAndRedrawPopup(); 143 } 144 145 void PasswordGenerationPopupControllerImpl::PasswordAccepted() { 146 if (!display_password_) 147 return; 148 149 web_contents()->GetRenderViewHost()->Send( 150 new AutofillMsg_GeneratedPasswordAccepted( 151 web_contents()->GetRenderViewHost()->GetRoutingID(), 152 current_password_)); 153 password_manager_->SetFormHasGeneratedPassword(form_); 154 Hide(); 155 } 156 157 int PasswordGenerationPopupControllerImpl::GetMinimumWidth() { 158 // Minimum width in pixels. 159 const int minimum_width = 350; 160 161 // If the width of the field is longer than the minimum, use that instead. 162 return std::max(minimum_width, 163 controller_common_.RoundedElementBounds().width()); 164 } 165 166 void PasswordGenerationPopupControllerImpl::CalculateBounds() { 167 gfx::Size bounds = view_->GetPreferredSizeOfPasswordView(); 168 169 popup_bounds_ = controller_common_.GetPopupBounds(bounds.width(), 170 bounds.height()); 171 } 172 173 void PasswordGenerationPopupControllerImpl::Show(bool display_password) { 174 display_password_ = display_password; 175 if (display_password_ && current_password_.empty()) 176 current_password_ = base::ASCIIToUTF16(generator_->Generate()); 177 178 if (!view_) { 179 view_ = PasswordGenerationPopupView::Create(this); 180 CalculateBounds(); 181 view_->Show(); 182 } else { 183 CalculateBounds(); 184 view_->UpdateBoundsAndRedrawPopup(); 185 } 186 187 controller_common_.RegisterKeyPressCallback(); 188 189 if (observer_) 190 observer_->OnPopupShown(display_password_); 191 } 192 193 void PasswordGenerationPopupControllerImpl::HideAndDestroy() { 194 Hide(); 195 } 196 197 void PasswordGenerationPopupControllerImpl::Hide() { 198 controller_common_.RemoveKeyPressCallback(); 199 200 if (view_) 201 view_->Hide(); 202 203 if (observer_) 204 observer_->OnPopupHidden(); 205 206 delete this; 207 } 208 209 void PasswordGenerationPopupControllerImpl::ViewDestroyed() { 210 view_ = NULL; 211 212 Hide(); 213 } 214 215 void PasswordGenerationPopupControllerImpl::OnSavedPasswordsLinkClicked() { 216 chrome::ShowSettingsSubPage( 217 chrome::FindBrowserWithWebContents(controller_common_.web_contents()), 218 chrome::kPasswordManagerSubPage); 219 } 220 221 void PasswordGenerationPopupControllerImpl::SetSelectionAtPoint( 222 const gfx::Point& point) { 223 PasswordSelected(view_->IsPointInPasswordBounds(point)); 224 } 225 226 bool PasswordGenerationPopupControllerImpl::AcceptSelectedLine() { 227 if (!password_selected_) 228 return false; 229 230 PasswordAccepted(); 231 return true; 232 } 233 234 void PasswordGenerationPopupControllerImpl::SelectionCleared() { 235 PasswordSelected(false); 236 } 237 238 gfx::NativeView PasswordGenerationPopupControllerImpl::container_view() { 239 return controller_common_.container_view(); 240 } 241 242 const gfx::Rect& PasswordGenerationPopupControllerImpl::popup_bounds() const { 243 return popup_bounds_; 244 } 245 246 bool PasswordGenerationPopupControllerImpl::display_password() const { 247 return display_password_; 248 } 249 250 bool PasswordGenerationPopupControllerImpl::password_selected() const { 251 return password_selected_; 252 } 253 254 base::string16 PasswordGenerationPopupControllerImpl::password() const { 255 return current_password_; 256 } 257 258 base::string16 PasswordGenerationPopupControllerImpl::SuggestedText() { 259 return l10n_util::GetStringUTF16(IDS_PASSWORD_GENERATION_SUGGESTION); 260 } 261 262 const base::string16& PasswordGenerationPopupControllerImpl::HelpText() { 263 return help_text_; 264 } 265 266 const gfx::Range& PasswordGenerationPopupControllerImpl::HelpTextLinkRange() { 267 return link_range_; 268 } 269 270 } // namespace autofill 271