Home | History | Annotate | Download | only in browser
      1 // Copyright 2013 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 "components/autofill/core/browser/autofill_external_delegate.h"
      6 
      7 #include "base/strings/utf_string_conversions.h"
      8 #include "components/autofill/core/browser/autocomplete_history_manager.h"
      9 #include "components/autofill/core/browser/autofill_driver.h"
     10 #include "components/autofill/core/browser/autofill_manager.h"
     11 #include "components/autofill/core/common/autofill_messages.h"
     12 #include "content/public/browser/render_view_host.h"
     13 #include "content/public/browser/web_contents.h"
     14 #include "grit/component_strings.h"
     15 #include "third_party/WebKit/public/web/WebAutofillClient.h"
     16 #include "ui/base/l10n/l10n_util.h"
     17 
     18 #if defined(OS_ANDROID)
     19 #include "content/public/browser/android/content_view_core.h"
     20 #endif
     21 
     22 using content::RenderViewHost;
     23 using WebKit::WebAutofillClient;
     24 
     25 namespace autofill {
     26 
     27 AutofillExternalDelegate::AutofillExternalDelegate(
     28     content::WebContents* web_contents,
     29     AutofillManager* autofill_manager,
     30     AutofillDriver* autofill_driver)
     31     : web_contents_(web_contents),
     32       autofill_manager_(autofill_manager),
     33       autofill_driver_(autofill_driver),
     34       password_autofill_manager_(web_contents),
     35       autofill_query_id_(0),
     36       display_warning_if_disabled_(false),
     37       has_autofill_suggestion_(false),
     38       has_shown_autofill_popup_for_current_edit_(false),
     39       registered_keyboard_listener_with_(NULL),
     40       weak_ptr_factory_(this) {
     41   DCHECK(autofill_manager);
     42 }
     43 
     44 AutofillExternalDelegate::~AutofillExternalDelegate() {}
     45 
     46 void AutofillExternalDelegate::OnQuery(int query_id,
     47                                        const FormData& form,
     48                                        const FormFieldData& field,
     49                                        const gfx::RectF& element_bounds,
     50                                        bool display_warning_if_disabled) {
     51   autofill_query_form_ = form;
     52   autofill_query_field_ = field;
     53   display_warning_if_disabled_ = display_warning_if_disabled;
     54   autofill_query_id_ = query_id;
     55   element_bounds_ = element_bounds;
     56 }
     57 
     58 void AutofillExternalDelegate::OnSuggestionsReturned(
     59     int query_id,
     60     const std::vector<base::string16>& autofill_values,
     61     const std::vector<base::string16>& autofill_labels,
     62     const std::vector<base::string16>& autofill_icons,
     63     const std::vector<int>& autofill_unique_ids) {
     64   if (query_id != autofill_query_id_)
     65     return;
     66 
     67   std::vector<base::string16> values(autofill_values);
     68   std::vector<base::string16> labels(autofill_labels);
     69   std::vector<base::string16> icons(autofill_icons);
     70   std::vector<int> ids(autofill_unique_ids);
     71 
     72   // Add or hide warnings as appropriate.
     73   ApplyAutofillWarnings(&values, &labels, &icons, &ids);
     74 
     75   // Add a separator to go between the values and menu items.
     76   values.push_back(base::string16());
     77   labels.push_back(base::string16());
     78   icons.push_back(base::string16());
     79   ids.push_back(WebAutofillClient::MenuItemIDSeparator);
     80 
     81   // Only include "Autofill Options" special menu item if we have Autofill
     82   // suggestions.
     83   has_autofill_suggestion_ = false;
     84   for (size_t i = 0; i < ids.size(); ++i) {
     85     if (ids[i] > 0) {
     86       has_autofill_suggestion_ = true;
     87       break;
     88     }
     89   }
     90 
     91   if (has_autofill_suggestion_)
     92     ApplyAutofillOptions(&values, &labels, &icons, &ids);
     93 
     94   // Remove the separator if it is the last element.
     95   DCHECK_GT(ids.size(), 0U);
     96   if (ids.back() == WebAutofillClient::MenuItemIDSeparator) {
     97     values.pop_back();
     98     labels.pop_back();
     99     icons.pop_back();
    100     ids.pop_back();
    101   }
    102 
    103   // If anything else is added to modify the values after inserting the data
    104   // list, AutofillPopupControllerImpl::UpdateDataListValues will need to be
    105   // updated to match.
    106   InsertDataListValues(&values, &labels, &icons, &ids);
    107 
    108   if (values.empty()) {
    109     // No suggestions, any popup currently showing is obsolete.
    110     autofill_manager_->delegate()->HideAutofillPopup();
    111     return;
    112   }
    113 
    114   // Send to display.
    115   if (autofill_query_field_.is_focusable) {
    116     autofill_manager_->delegate()->ShowAutofillPopup(
    117         element_bounds_,
    118         autofill_query_field_.text_direction,
    119         values,
    120         labels,
    121         icons,
    122         ids,
    123         GetWeakPtr());
    124   }
    125 }
    126 
    127 void AutofillExternalDelegate::OnShowPasswordSuggestions(
    128     const std::vector<base::string16>& suggestions,
    129     const std::vector<base::string16>& realms,
    130     const FormFieldData& field,
    131     const gfx::RectF& element_bounds) {
    132   autofill_query_field_ = field;
    133   element_bounds_ = element_bounds;
    134 
    135   if (suggestions.empty()) {
    136     autofill_manager_->delegate()->HideAutofillPopup();
    137     return;
    138   }
    139 
    140   std::vector<base::string16> empty(suggestions.size());
    141   std::vector<int> password_ids(suggestions.size(),
    142                                 WebAutofillClient::MenuItemIDPasswordEntry);
    143   autofill_manager_->delegate()->ShowAutofillPopup(
    144       element_bounds_,
    145       autofill_query_field_.text_direction,
    146       suggestions,
    147       realms,
    148       empty,
    149       password_ids,
    150       GetWeakPtr());
    151 }
    152 
    153 void AutofillExternalDelegate::SetCurrentDataListValues(
    154     const std::vector<base::string16>& data_list_values,
    155     const std::vector<base::string16>& data_list_labels) {
    156   data_list_values_ = data_list_values;
    157   data_list_labels_ = data_list_labels;
    158 
    159   autofill_manager_->delegate()->UpdateAutofillPopupDataListValues(
    160       data_list_values,
    161       data_list_labels);
    162 }
    163 
    164 void AutofillExternalDelegate::OnPopupShown(
    165     content::KeyboardListener* listener) {
    166   if (!registered_keyboard_listener_with_) {
    167     registered_keyboard_listener_with_ = web_contents_->GetRenderViewHost();
    168     registered_keyboard_listener_with_->AddKeyboardListener(listener);
    169   }
    170 
    171   autofill_manager_->OnDidShowAutofillSuggestions(
    172       has_autofill_suggestion_ && !has_shown_autofill_popup_for_current_edit_);
    173   has_shown_autofill_popup_for_current_edit_ |= has_autofill_suggestion_;
    174 }
    175 
    176 void AutofillExternalDelegate::OnPopupHidden(
    177     content::KeyboardListener* listener) {
    178   if ((!web_contents_->IsBeingDestroyed()) &&
    179       (registered_keyboard_listener_with_ ==
    180           web_contents_->GetRenderViewHost())) {
    181     web_contents_->GetRenderViewHost()->RemoveKeyboardListener(listener);
    182   }
    183 
    184   registered_keyboard_listener_with_ = NULL;
    185 }
    186 
    187 void AutofillExternalDelegate::DidSelectSuggestion(int identifier) {
    188   ClearPreviewedForm();
    189 
    190   // Only preview the data if it is a profile.
    191   if (identifier > 0)
    192     FillAutofillFormData(identifier, true);
    193 }
    194 
    195 void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value,
    196                                                    int identifier) {
    197   RenderViewHost* host = web_contents_->GetRenderViewHost();
    198 
    199   if (identifier == WebAutofillClient::MenuItemIDAutofillOptions) {
    200     // User selected 'Autofill Options'.
    201     autofill_manager_->OnShowAutofillDialog();
    202   } else if (identifier == WebAutofillClient::MenuItemIDClearForm) {
    203     // User selected 'Clear form'.
    204     autofill_driver_->RendererShouldClearFilledForm();
    205   } else if (identifier == WebAutofillClient::MenuItemIDPasswordEntry) {
    206     bool success = password_autofill_manager_.DidAcceptAutofillSuggestion(
    207         autofill_query_field_, value);
    208     DCHECK(success);
    209   } else if (identifier == WebAutofillClient::MenuItemIDDataListEntry) {
    210     host->Send(new AutofillMsg_AcceptDataListSuggestion(host->GetRoutingID(),
    211                                                         value));
    212   } else if (identifier == WebAutofillClient::MenuItemIDAutocompleteEntry) {
    213     // User selected an Autocomplete, so we fill directly.
    214     host->Send(new AutofillMsg_SetNodeText(host->GetRoutingID(), value));
    215   } else {
    216     FillAutofillFormData(identifier, false);
    217   }
    218 
    219   autofill_manager_->delegate()->HideAutofillPopup();
    220 }
    221 
    222 void AutofillExternalDelegate::RemoveSuggestion(const base::string16& value,
    223                                                 int identifier) {
    224   if (identifier > 0) {
    225     autofill_manager_->RemoveAutofillProfileOrCreditCard(identifier);
    226   } else {
    227     autofill_manager_->RemoveAutocompleteEntry(autofill_query_field_.name,
    228                                                value);
    229   }
    230 }
    231 
    232 void AutofillExternalDelegate::DidEndTextFieldEditing() {
    233   autofill_manager_->delegate()->HideAutofillPopup();
    234 
    235   has_shown_autofill_popup_for_current_edit_ = false;
    236 }
    237 
    238 void AutofillExternalDelegate::ClearPreviewedForm() {
    239   autofill_driver_->RendererShouldClearPreviewedForm();
    240 }
    241 
    242 void AutofillExternalDelegate::Reset() {
    243   autofill_manager_->delegate()->HideAutofillPopup();
    244 
    245   password_autofill_manager_.Reset();
    246 }
    247 
    248 void AutofillExternalDelegate::AddPasswordFormMapping(
    249       const FormFieldData& form,
    250       const PasswordFormFillData& fill_data) {
    251   password_autofill_manager_.AddPasswordFormMapping(form, fill_data);
    252 }
    253 
    254 base::WeakPtr<AutofillExternalDelegate> AutofillExternalDelegate::GetWeakPtr() {
    255   return weak_ptr_factory_.GetWeakPtr();
    256 }
    257 
    258 void AutofillExternalDelegate::FillAutofillFormData(int unique_id,
    259                                                     bool is_preview) {
    260   // If the selected element is a warning we don't want to do anything.
    261   if (unique_id == WebAutofillClient::MenuItemIDWarningMessage)
    262     return;
    263 
    264   AutofillDriver::RendererFormDataAction renderer_action = is_preview ?
    265       AutofillDriver::FORM_DATA_ACTION_PREVIEW :
    266       AutofillDriver::FORM_DATA_ACTION_FILL;
    267 
    268   DCHECK(autofill_driver_->RendererIsAvailable());
    269   autofill_driver_->SetRendererActionOnFormDataReception(renderer_action);
    270   // Fill the values for the whole form.
    271   autofill_manager_->OnFillAutofillFormData(autofill_query_id_,
    272                                             autofill_query_form_,
    273                                             autofill_query_field_,
    274                                             unique_id);
    275 }
    276 
    277 void AutofillExternalDelegate::ApplyAutofillWarnings(
    278     std::vector<base::string16>* autofill_values,
    279     std::vector<base::string16>* autofill_labels,
    280     std::vector<base::string16>* autofill_icons,
    281     std::vector<int>* autofill_unique_ids) {
    282   if (!autofill_query_field_.should_autocomplete) {
    283     // Autofill is disabled.  If there were some profile or credit card
    284     // suggestions to show, show a warning instead.  Otherwise, clear out the
    285     // list of suggestions.
    286     if (!autofill_unique_ids->empty() && (*autofill_unique_ids)[0] > 0) {
    287       // If autofill is disabled and we had suggestions, show a warning instead.
    288       autofill_values->assign(
    289           1, l10n_util::GetStringUTF16(IDS_AUTOFILL_WARNING_FORM_DISABLED));
    290       autofill_labels->assign(1, base::string16());
    291       autofill_icons->assign(1, base::string16());
    292       autofill_unique_ids->assign(1,
    293                                   WebAutofillClient::MenuItemIDWarningMessage);
    294     } else {
    295       autofill_values->clear();
    296       autofill_labels->clear();
    297       autofill_icons->clear();
    298       autofill_unique_ids->clear();
    299     }
    300   } else if (autofill_unique_ids->size() > 1 &&
    301              (*autofill_unique_ids)[0] ==
    302                  WebAutofillClient::MenuItemIDWarningMessage) {
    303     // If we received a warning instead of suggestions from autofill but regular
    304     // suggestions from autocomplete, don't show the autofill warning.
    305     autofill_values->erase(autofill_values->begin());
    306     autofill_labels->erase(autofill_labels->begin());
    307     autofill_icons->erase(autofill_icons->begin());
    308     autofill_unique_ids->erase(autofill_unique_ids->begin());
    309   }
    310 
    311   // If we were about to show a warning and we shouldn't, don't.
    312   if (!autofill_unique_ids->empty() &&
    313       (*autofill_unique_ids)[0] ==
    314           WebAutofillClient::MenuItemIDWarningMessage &&
    315       !display_warning_if_disabled_) {
    316     autofill_values->clear();
    317     autofill_labels->clear();
    318     autofill_icons->clear();
    319     autofill_unique_ids->clear();
    320   }
    321 }
    322 
    323 void AutofillExternalDelegate::ApplyAutofillOptions(
    324     std::vector<base::string16>* autofill_values,
    325     std::vector<base::string16>* autofill_labels,
    326     std::vector<base::string16>* autofill_icons,
    327     std::vector<int>* autofill_unique_ids) {
    328   // The form has been auto-filled, so give the user the chance to clear the
    329   // form.  Append the 'Clear form' menu item.
    330   if (autofill_query_field_.is_autofilled) {
    331     autofill_values->push_back(
    332         l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM));
    333     autofill_labels->push_back(base::string16());
    334     autofill_icons->push_back(base::string16());
    335     autofill_unique_ids->push_back(WebAutofillClient::MenuItemIDClearForm);
    336   }
    337 
    338   // Append the 'Chrome Autofill options' menu item;
    339   autofill_values->push_back(
    340       l10n_util::GetStringUTF16(IDS_AUTOFILL_OPTIONS_POPUP));
    341   autofill_labels->push_back(base::string16());
    342   autofill_icons->push_back(base::string16());
    343   autofill_unique_ids->push_back(WebAutofillClient::MenuItemIDAutofillOptions);
    344 }
    345 
    346 void AutofillExternalDelegate::InsertDataListValues(
    347     std::vector<base::string16>* autofill_values,
    348     std::vector<base::string16>* autofill_labels,
    349     std::vector<base::string16>* autofill_icons,
    350     std::vector<int>* autofill_unique_ids) {
    351   if (data_list_values_.empty())
    352     return;
    353 
    354   // Insert the separator between the datalist and Autofill values (if there
    355   // are any).
    356   if (!autofill_values->empty()) {
    357     autofill_values->insert(autofill_values->begin(), base::string16());
    358     autofill_labels->insert(autofill_labels->begin(), base::string16());
    359     autofill_icons->insert(autofill_icons->begin(), base::string16());
    360     autofill_unique_ids->insert(autofill_unique_ids->begin(),
    361                                 WebAutofillClient::MenuItemIDSeparator);
    362   }
    363 
    364   // Insert the datalist elements.
    365   autofill_values->insert(autofill_values->begin(),
    366                           data_list_values_.begin(),
    367                           data_list_values_.end());
    368   autofill_labels->insert(autofill_labels->begin(),
    369                           data_list_labels_.begin(),
    370                           data_list_labels_.end());
    371 
    372   // Set the values that all datalist elements share.
    373   autofill_icons->insert(autofill_icons->begin(),
    374                          data_list_values_.size(),
    375                          base::string16());
    376   autofill_unique_ids->insert(autofill_unique_ids->begin(),
    377                               data_list_values_.size(),
    378                               WebAutofillClient::MenuItemIDDataListEntry);
    379 }
    380 
    381 }  // namespace autofill
    382