Commit b5093a79 authored by estade@chromium.org's avatar estade@chromium.org

allow wallet items to appear in requestAutocomplete UI

this CL adds a glue interface so that AutofillDialogController can be more agnostic about where its data is coming from.

BUG=174937
TBR=thestig@chromium.org
committed

Review URL: https://codereview.chromium.org/12208070

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@182348 0039d316-1c4b-4281-b951-d872f2087c98
parent 17d81248
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "chrome/browser/autofill/wallet/wallet_address.h" #include "chrome/browser/autofill/wallet/wallet_address.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/utf_string_conversions.h"
#include "base/values.h" #include "base/values.h"
namespace wallet { namespace wallet {
...@@ -62,6 +63,37 @@ scoped_ptr<base::DictionaryValue> Address::ToDictionaryWithoutID() const { ...@@ -62,6 +63,37 @@ scoped_ptr<base::DictionaryValue> Address::ToDictionaryWithoutID() const {
return dict.Pass(); return dict.Pass();
} }
string16 Address::DisplayName() const {
// TODO(estade): improve this stub implementation.
return UTF8ToUTF16(recipient_name() + ", " + address_line_1());
}
string16 Address::GetInfo(AutofillFieldType type) const {
switch (type) {
case NAME_FULL:
return UTF8ToUTF16(recipient_name());
case ADDRESS_HOME_LINE1:
return UTF8ToUTF16(address_line_1());
case ADDRESS_HOME_LINE2:
return UTF8ToUTF16(address_line_2());
case ADDRESS_HOME_CITY:
return UTF8ToUTF16(locality_name());
case ADDRESS_HOME_STATE:
return UTF8ToUTF16(admin_area_name());
case ADDRESS_HOME_ZIP:
return UTF8ToUTF16(postal_code_number());
// TODO(estade): implement more.
default:
NOTREACHED();
return string16();
}
}
scoped_ptr<Address> scoped_ptr<Address>
Address::CreateAddressWithID(const base::DictionaryValue& dictionary) { Address::CreateAddressWithID(const base::DictionaryValue& dictionary) {
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/string16.h"
#include "chrome/browser/autofill/field_types.h"
namespace base { namespace base {
class DictionaryValue; class DictionaryValue;
...@@ -87,6 +89,13 @@ class Address { ...@@ -87,6 +89,13 @@ class Address {
// sent to the server in a slightly different format. // sent to the server in a slightly different format.
scoped_ptr<base::DictionaryValue> ToDictionaryWithoutID() const; scoped_ptr<base::DictionaryValue> ToDictionaryWithoutID() const;
// Returns a string that summarizes this address, suitable for display to
// the user.
string16 DisplayName() const;
// Returns data appropriate for |type|.
string16 GetInfo(AutofillFieldType type) const;
// Returns an empty scoped_ptr if input is invalid or a valid address that is // Returns an empty scoped_ptr if input is invalid or a valid address that is
// selectable for Google Wallet use. // selectable for Google Wallet use.
static scoped_ptr<Address> static scoped_ptr<Address>
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <string> #include <string>
#include "base/logging.h" #include "base/logging.h"
#include "base/string_number_conversions.h"
#include "base/string_split.h" #include "base/string_split.h"
#include "base/string_util.h" #include "base/string_util.h"
#include "base/utf_string_conversions.h" #include "base/utf_string_conversions.h"
...@@ -21,6 +22,7 @@ ...@@ -21,6 +22,7 @@
#include "chrome/browser/autofill/wallet/wallet_service_url.h" #include "chrome/browser/autofill/wallet/wallet_service_url.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/autofill/autofill_dialog_view.h" #include "chrome/browser/ui/autofill/autofill_dialog_view.h"
#include "chrome/browser/ui/autofill/data_model_wrapper.h"
#include "chrome/common/form_data.h" #include "chrome/common/form_data.h"
#include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_details.h" #include "content/public/browser/navigation_details.h"
...@@ -378,24 +380,51 @@ string16 AutofillDialogControllerImpl::SuggestionTextForSection( ...@@ -378,24 +380,51 @@ string16 AutofillDialogControllerImpl::SuggestionTextForSection(
if (section == SECTION_EMAIL) if (section == SECTION_EMAIL)
return model->GetLabelAt(model->checked_item()); return model->GetLabelAt(model->checked_item());
if (section == SECTION_CC) { scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
return wrapper->GetDisplayText();
}
scoped_ptr<DataModelWrapper> AutofillDialogControllerImpl::CreateWrapper(
DialogSection section) {
SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
std::string item_key = model->GetItemKeyAt(model->checked_item());
scoped_ptr<DataModelWrapper> wrapper;
if (item_key.empty())
return wrapper.Pass();
if (CanPayWithWallet()) {
int index;
bool success = !base::StringToInt(item_key, &index);
DCHECK(success);
if (section == SECTION_CC) {
wrapper.reset(
new WalletInstrumentWrapper(wallet_items_->instruments()[index]));
} else {
wrapper.reset(
new WalletAddressWrapper(wallet_items_->addresses()[index]));
}
} else if (section == SECTION_CC) {
CreditCard* card = GetManager()->GetCreditCardByGUID(item_key); CreditCard* card = GetManager()->GetCreditCardByGUID(item_key);
return card->TypeAndLastFourDigits(); DCHECK(card);
wrapper.reset(new AutofillCreditCardWrapper(card));
} else {
// Calculate the variant by looking at how many items come from the same
// FormGroup. TODO(estade): add a test for this.
size_t variant = 0;
for (int i = model->checked_item() - 1; i >= 0; --i) {
if (model->GetItemKeyAt(i) == item_key)
variant++;
else
break;
}
AutofillProfile* profile = GetManager()->GetProfileByGUID(item_key);
DCHECK(profile);
wrapper.reset(new AutofillDataModelWrapper(profile, variant));
} }
const std::string app_locale = AutofillCountry::ApplicationLocale(); return wrapper.Pass();
AutofillProfile* profile = GetManager()->GetProfileByGUID(item_key);
string16 comma = ASCIIToUTF16(", ");
string16 label = profile->GetInfo(NAME_FULL, app_locale) +
comma + profile->GetInfo(ADDRESS_HOME_LINE1, app_locale);
string16 address2 = profile->GetInfo(ADDRESS_HOME_LINE2, app_locale);
if (!address2.empty())
label += comma + address2;
label += ASCIIToUTF16("\n") +
profile->GetInfo(ADDRESS_HOME_CITY, app_locale) + comma +
profile->GetInfo(ADDRESS_HOME_STATE, app_locale) + ASCIIToUTF16(" ") +
profile->GetInfo(ADDRESS_HOME_ZIP, app_locale);
return label;
} }
gfx::Image AutofillDialogControllerImpl::SuggestionIconForSection( gfx::Image AutofillDialogControllerImpl::SuggestionIconForSection(
...@@ -403,13 +432,11 @@ gfx::Image AutofillDialogControllerImpl::SuggestionIconForSection( ...@@ -403,13 +432,11 @@ gfx::Image AutofillDialogControllerImpl::SuggestionIconForSection(
if (section != SECTION_CC) if (section != SECTION_CC)
return gfx::Image(); return gfx::Image();
std::string item_key = scoped_ptr<DataModelWrapper> model = CreateWrapper(section);
suggested_cc_.GetItemKeyAt(suggested_cc_.checked_item()); if (!model.get())
if (item_key.empty())
return gfx::Image(); return gfx::Image();
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
CreditCard* card = GetManager()->GetCreditCardByGUID(item_key); return model->GetIcon();
return rb.GetImageNamed(card->IconResourceId());
} }
void AutofillDialogControllerImpl::EditClickedForSection( void AutofillDialogControllerImpl::EditClickedForSection(
...@@ -424,14 +451,8 @@ void AutofillDialogControllerImpl::EditClickedForSection( ...@@ -424,14 +451,8 @@ void AutofillDialogControllerImpl::EditClickedForSection(
(*inputs)[0].autofilled_value = model->GetLabelAt(model->checked_item()); (*inputs)[0].autofilled_value = model->GetLabelAt(model->checked_item());
} else { } else {
std::string guid = model->GetItemKeyAt(model->checked_item()); scoped_ptr<DataModelWrapper> model = CreateWrapper(section);
DCHECK(!guid.empty()); model->FillInputs(inputs);
FormGroup* form_group = section == SECTION_CC ?
static_cast<FormGroup*>(GetManager()->GetCreditCardByGUID(guid)) :
static_cast<FormGroup*>(GetManager()->GetProfileByGUID(guid));
DCHECK(form_group);
FillInputFromFormGroup(form_group, inputs);
} }
section_editing_state_[section] = true; section_editing_state_[section] = true;
...@@ -720,6 +741,8 @@ void AutofillDialogControllerImpl::OnDidGetWalletItems( ...@@ -720,6 +741,8 @@ void AutofillDialogControllerImpl::OnDidGetWalletItems(
WalletRequestCompleted(true); WalletRequestCompleted(true);
if (items_changed) { if (items_changed) {
GenerateSuggestionsModels();
view_->ModelChanged();
view_->UpdateAccountChooser(); view_->UpdateAccountChooser();
view_->UpdateNotificationArea(); view_->UpdateNotificationArea();
} }
...@@ -830,6 +853,8 @@ void AutofillDialogControllerImpl::WalletRequestCompleted(bool success) { ...@@ -830,6 +853,8 @@ void AutofillDialogControllerImpl::WalletRequestCompleted(bool success) {
if (!success) { if (!success) {
had_wallet_error_ = true; had_wallet_error_ = true;
wallet_items_.reset(); wallet_items_.reset();
GenerateSuggestionsModels();
view_->ModelChanged();
view_->UpdateAccountChooser(); view_->UpdateAccountChooser();
view_->UpdateNotificationArea(); view_->UpdateNotificationArea();
return; return;
...@@ -845,30 +870,49 @@ void AutofillDialogControllerImpl::GenerateSuggestionsModels() { ...@@ -845,30 +870,49 @@ void AutofillDialogControllerImpl::GenerateSuggestionsModels() {
suggested_email_.Reset(); suggested_email_.Reset();
suggested_shipping_.Reset(); suggested_shipping_.Reset();
PersonalDataManager* manager = GetManager(); if (CanPayWithWallet()) {
const std::vector<CreditCard*>& cards = manager->credit_cards(); if (wallet_items_.get()) {
for (size_t i = 0; i < cards.size(); ++i) { // TODO(estade): seems we need to hardcode the email address.
suggested_cc_.AddKeyedItem(cards[i]->guid(), cards[i]->Label()); // TODO(estade): CC and billing need to be combined into one section,
} // and suggestions added here.
const std::vector<wallet::Address*>& addresses =
const std::vector<AutofillProfile*>& profiles = manager->GetProfiles(); wallet_items_->addresses();
const std::string app_locale = AutofillCountry::ApplicationLocale(); for (size_t i = 0; i < addresses.size(); ++i) {
for (size_t i = 0; i < profiles.size(); ++i) { suggested_billing_.AddKeyedItem(base::IntToString(i),
if (!IsCompleteProfile(*profiles[i])) addresses[i]->DisplayName());
continue; suggested_shipping_.AddKeyedItem(base::IntToString(i),
addresses[i]->DisplayName());
// Add all email addresses. }
std::vector<string16> values; }
profiles[i]->GetMultiInfo(EMAIL_ADDRESS, app_locale, &values); } else {
for (size_t j = 0; j < values.size(); ++j) { PersonalDataManager* manager = GetManager();
if (!values[j].empty()) const std::vector<CreditCard*>& cards = manager->credit_cards();
suggested_email_.AddKeyedItem(profiles[i]->guid(), values[j]); for (size_t i = 0; i < cards.size(); ++i) {
suggested_cc_.AddKeyedItem(cards[i]->guid(), cards[i]->Label());
} }
// Don't add variants for addresses: the email variants are handled above, const std::vector<AutofillProfile*>& profiles = manager->GetProfiles();
// name is part of credit card and we'll just ignore phone number variants. const std::string app_locale = AutofillCountry::ApplicationLocale();
suggested_billing_.AddKeyedItem(profiles[i]->guid(), profiles[i]->Label()); for (size_t i = 0; i < profiles.size(); ++i) {
suggested_shipping_.AddKeyedItem(profiles[i]->guid(), profiles[i]->Label()); if (!IsCompleteProfile(*profiles[i]))
continue;
// Add all email addresses.
std::vector<string16> values;
profiles[i]->GetMultiInfo(EMAIL_ADDRESS, app_locale, &values);
for (size_t j = 0; j < values.size(); ++j) {
if (!values[j].empty())
suggested_email_.AddKeyedItem(profiles[i]->guid(), values[j]);
}
// Don't add variants for addresses: the email variants are handled above,
// name is part of credit card and we'll just ignore phone number
// variants.
suggested_billing_.AddKeyedItem(profiles[i]->guid(),
profiles[i]->Label());
suggested_shipping_.AddKeyedItem(profiles[i]->guid(),
profiles[i]->Label());
}
} }
suggested_email_.AddKeyedItem( suggested_email_.AddKeyedItem(
...@@ -902,25 +946,12 @@ void AutofillDialogControllerImpl::FillOutputForSectionWithComparator( ...@@ -902,25 +946,12 @@ void AutofillDialogControllerImpl::FillOutputForSectionWithComparator(
DialogSection section, DialogSection section,
const InputFieldComparator& compare) { const InputFieldComparator& compare) {
SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section); SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
std::string guid = model->GetItemKeyAt(model->checked_item()); std::string item_key = model->GetItemKeyAt(model->checked_item());
PersonalDataManager* manager = GetManager(); if (!item_key.empty() && !section_editing_state_[section]) {
if (!guid.empty() && !section_editing_state_[section]) { scoped_ptr<DataModelWrapper> model = CreateWrapper(section);
FormGroup* form_group = section == SECTION_CC ? // Only fill in data that is associated with this section.
static_cast<FormGroup*>(manager->GetCreditCardByGUID(guid)) : const DetailInputs& inputs = RequestedFieldsForSection(section);
static_cast<FormGroup*>(manager->GetProfileByGUID(guid)); model->FillFormStructure(inputs, compare, &form_structure_);
DCHECK(form_group);
// Calculate the variant by looking at how many items come from the same
// FormGroup. TODO(estade): add a test for this.
size_t variant = 0;
for (int i = model->checked_item() - 1; i >= 0; --i) {
if (model->GetItemKeyAt(i) == guid)
variant++;
else
break;
}
FillFormStructureForSection(*form_group, variant, section, compare);
// CVC needs special-casing because the CreditCard class doesn't store // CVC needs special-casing because the CreditCard class doesn't store
// or handle them. // or handle them.
...@@ -928,6 +959,7 @@ void AutofillDialogControllerImpl::FillOutputForSectionWithComparator( ...@@ -928,6 +959,7 @@ void AutofillDialogControllerImpl::FillOutputForSectionWithComparator(
SetCvcResult(view_->GetCvc()); SetCvcResult(view_->GetCvc());
} else { } else {
// The user manually input data. // The user manually input data.
PersonalDataManager* manager = GetManager();
DetailOutputMap output; DetailOutputMap output;
view_->GetUserInput(section, &output); view_->GetUserInput(section, &output);
......
...@@ -40,6 +40,7 @@ class WebContents; ...@@ -40,6 +40,7 @@ class WebContents;
namespace autofill { namespace autofill {
class AutofillDialogView; class AutofillDialogView;
class DataModelWrapper;
// This class drives the dialog that appears when a site uses the imperative // This class drives the dialog that appears when a site uses the imperative
// autocomplete API to fill out a form. // autocomplete API to fill out a form.
...@@ -149,10 +150,6 @@ class AutofillDialogControllerImpl : public AutofillDialogController, ...@@ -149,10 +150,6 @@ class AutofillDialogControllerImpl : public AutofillDialogController,
virtual void OnPersonalDataChanged() OVERRIDE; virtual void OnPersonalDataChanged() OVERRIDE;
private: private:
// Determines whether |input| and |field| match.
typedef base::Callback<bool(const DetailInput& input,
const AutofillField& field)> InputFieldComparator;
// Refresh wallet items immediately if there's no refresh currently in // Refresh wallet items immediately if there's no refresh currently in
// progress, otherwise wait until the current refresh completes. // progress, otherwise wait until the current refresh completes.
void ScheduleRefreshWalletItems(); void ScheduleRefreshWalletItems();
...@@ -180,6 +177,11 @@ class AutofillDialogControllerImpl : public AutofillDialogController, ...@@ -180,6 +177,11 @@ class AutofillDialogControllerImpl : public AutofillDialogController,
// menu. // menu.
bool IsCompleteProfile(const AutofillProfile& profile); bool IsCompleteProfile(const AutofillProfile& profile);
// Creates a DataModelWrapper item for the item that's checked in the
// suggestion model for |section|. This may represent Autofill
// data or Wallet data, depending on whether Wallet is currently enabled.
scoped_ptr<DataModelWrapper> CreateWrapper(DialogSection section);
// Fills in |section|-related fields in |output_| according to the state of // Fills in |section|-related fields in |output_| according to the state of
// |view_|. // |view_|.
void FillOutputForSection(DialogSection section); void FillOutputForSection(DialogSection section);
......
...@@ -8,10 +8,13 @@ ...@@ -8,10 +8,13 @@
#include <map> #include <map>
#include <vector> #include <vector>
#include "base/callback_forward.h"
#include "base/string16.h" #include "base/string16.h"
#include "chrome/browser/autofill/field_types.h" #include "chrome/browser/autofill/field_types.h"
#include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkColor.h"
class AutofillField;
namespace autofill { namespace autofill {
// This struct describes a single input control for the imperative autocomplete // This struct describes a single input control for the imperative autocomplete
...@@ -34,6 +37,10 @@ struct DetailInput { ...@@ -34,6 +37,10 @@ struct DetailInput {
string16 autofilled_value; string16 autofilled_value;
}; };
// Determines whether |input| and |field| match.
typedef base::Callback<bool(const DetailInput& input,
const AutofillField& field)> InputFieldComparator;
// Sections of the dialog --- all fields that may be shown to the user fit under // Sections of the dialog --- all fields that may be shown to the user fit under
// one of these sections. // one of these sections.
enum DialogSection { enum DialogSection {
......
...@@ -219,6 +219,8 @@ ...@@ -219,6 +219,8 @@
'browser/ui/autofill/autofill_popup_controller_impl.h', 'browser/ui/autofill/autofill_popup_controller_impl.h',
'browser/ui/autofill/autofill_popup_delegate.h', 'browser/ui/autofill/autofill_popup_delegate.h',
'browser/ui/autofill/autofill_popup_view.h', 'browser/ui/autofill/autofill_popup_view.h',
'browser/ui/autofill/data_model_wrapper.cc',
'browser/ui/autofill/data_model_wrapper.h',
'browser/ui/autofill/tab_autofill_manager_delegate.cc', 'browser/ui/autofill/tab_autofill_manager_delegate.cc',
'browser/ui/autofill/tab_autofill_manager_delegate.h', 'browser/ui/autofill/tab_autofill_manager_delegate.h',
'browser/ui/auto_login_info_bar_delegate.cc', 'browser/ui/auto_login_info_bar_delegate.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment