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 33namespace autofill { 34 35base::WeakPtr<PasswordGenerationPopupControllerImpl> 36PasswordGenerationPopupControllerImpl::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 67PasswordGenerationPopupControllerImpl::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 99PasswordGenerationPopupControllerImpl::~PasswordGenerationPopupControllerImpl() 100 {} 101 102base::WeakPtr<PasswordGenerationPopupControllerImpl> 103PasswordGenerationPopupControllerImpl::GetWeakPtr() { 104 return weak_ptr_factory_.GetWeakPtr(); 105} 106 107bool 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 127bool PasswordGenerationPopupControllerImpl::PossiblyAcceptPassword() { 128 if (password_selected_) { 129 PasswordAccepted(); // This will delete |this|. 130 return true; 131 } 132 133 return false; 134} 135 136void 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 145void 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 157int 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 166void PasswordGenerationPopupControllerImpl::CalculateBounds() { 167 gfx::Size bounds = view_->GetPreferredSizeOfPasswordView(); 168 169 popup_bounds_ = controller_common_.GetPopupBounds(bounds.width(), 170 bounds.height()); 171} 172 173void 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 193void PasswordGenerationPopupControllerImpl::HideAndDestroy() { 194 Hide(); 195} 196 197void 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 209void PasswordGenerationPopupControllerImpl::ViewDestroyed() { 210 view_ = NULL; 211 212 Hide(); 213} 214 215void PasswordGenerationPopupControllerImpl::OnSavedPasswordsLinkClicked() { 216 chrome::ShowSettingsSubPage( 217 chrome::FindBrowserWithWebContents(controller_common_.web_contents()), 218 chrome::kPasswordManagerSubPage); 219} 220 221void PasswordGenerationPopupControllerImpl::SetSelectionAtPoint( 222 const gfx::Point& point) { 223 PasswordSelected(view_->IsPointInPasswordBounds(point)); 224} 225 226bool PasswordGenerationPopupControllerImpl::AcceptSelectedLine() { 227 if (!password_selected_) 228 return false; 229 230 PasswordAccepted(); 231 return true; 232} 233 234void PasswordGenerationPopupControllerImpl::SelectionCleared() { 235 PasswordSelected(false); 236} 237 238gfx::NativeView PasswordGenerationPopupControllerImpl::container_view() { 239 return controller_common_.container_view(); 240} 241 242const gfx::Rect& PasswordGenerationPopupControllerImpl::popup_bounds() const { 243 return popup_bounds_; 244} 245 246bool PasswordGenerationPopupControllerImpl::display_password() const { 247 return display_password_; 248} 249 250bool PasswordGenerationPopupControllerImpl::password_selected() const { 251 return password_selected_; 252} 253 254base::string16 PasswordGenerationPopupControllerImpl::password() const { 255 return current_password_; 256} 257 258base::string16 PasswordGenerationPopupControllerImpl::SuggestedText() { 259 return l10n_util::GetStringUTF16(IDS_PASSWORD_GENERATION_SUGGESTION); 260} 261 262const base::string16& PasswordGenerationPopupControllerImpl::HelpText() { 263 return help_text_; 264} 265 266const gfx::Range& PasswordGenerationPopupControllerImpl::HelpTextLinkRange() { 267 return link_range_; 268} 269 270} // namespace autofill 271