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