Home | History | Annotate | Download | only in autofill
      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