Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(822)

Side by Side Diff: chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc

Issue 15500008: Persist the choice of AutofillDataModel when using the requestAutocomplete dialog. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: ilya review Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h" 5 #include "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/prefs/pref_service.h" 12 #include "base/prefs/pref_service.h"
13 #include "base/string_util.h" 13 #include "base/string_util.h"
14 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_split.h" 15 #include "base/strings/string_split.h"
16 #include "base/time.h" 16 #include "base/time.h"
17 #include "base/utf_string_conversions.h" 17 #include "base/utf_string_conversions.h"
18 #include "chrome/browser/autofill/personal_data_manager_factory.h" 18 #include "chrome/browser/autofill/personal_data_manager_factory.h"
19 #include "chrome/browser/browser_process.h" 19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/extensions/shell_window_registry.h" 20 #include "chrome/browser/extensions/shell_window_registry.h"
21 #include "chrome/browser/prefs/scoped_user_pref_update.h"
21 #include "chrome/browser/profiles/profile.h" 22 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ui/autofill/autofill_dialog_view.h" 23 #include "chrome/browser/ui/autofill/autofill_dialog_view.h"
23 #include "chrome/browser/ui/autofill/data_model_wrapper.h" 24 #include "chrome/browser/ui/autofill/data_model_wrapper.h"
24 #include "chrome/browser/ui/base_window.h" 25 #include "chrome/browser/ui/base_window.h"
25 #include "chrome/browser/ui/browser.h" 26 #include "chrome/browser/ui/browser.h"
26 #include "chrome/browser/ui/browser_finder.h" 27 #include "chrome/browser/ui/browser_finder.h"
27 #include "chrome/browser/ui/browser_navigator.h" 28 #include "chrome/browser/ui/browser_navigator.h"
28 #include "chrome/browser/ui/browser_window.h" 29 #include "chrome/browser/ui/browser_window.h"
29 #include "chrome/browser/ui/extensions/native_app_window.h" 30 #include "chrome/browser/ui/extensions/native_app_window.h"
30 #include "chrome/browser/ui/extensions/shell_window.h" 31 #include "chrome/browser/ui/extensions/shell_window.h"
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 // special value to the server to just ask for the maximum so we don't need to 80 // special value to the server to just ask for the maximum so we don't need to
80 // hardcode it here (http://crbug.com/180731). TODO(dbeam): also maybe allow 81 // hardcode it here (http://crbug.com/180731). TODO(dbeam): also maybe allow
81 // users to give us this number via an <input> (http://crbug.com/180733). 82 // users to give us this number via an <input> (http://crbug.com/180733).
82 const int kCartMax = 1850; 83 const int kCartMax = 1850;
83 const char kCartCurrency[] = "USD"; 84 const char kCartCurrency[] = "USD";
84 85
85 const char kAddNewItemKey[] = "add-new-item"; 86 const char kAddNewItemKey[] = "add-new-item";
86 const char kManageItemsKey[] = "manage-items"; 87 const char kManageItemsKey[] = "manage-items";
87 const char kSameAsBillingKey[] = "same-as-billing"; 88 const char kSameAsBillingKey[] = "same-as-billing";
88 89
90 // Keys for the kAutofillDialogAutofillDefault pref dictionary (do not change
91 // these values).
92 const char kGuidPrefKey[] = "guid";
93 const char kVariantPrefKey[] = "variant";
94
89 // Returns true if |input| should be shown when |field_type| has been requested. 95 // Returns true if |input| should be shown when |field_type| has been requested.
90 bool InputTypeMatchesFieldType(const DetailInput& input, 96 bool InputTypeMatchesFieldType(const DetailInput& input,
91 AutofillFieldType field_type) { 97 AutofillFieldType field_type) {
92 // If any credit card expiration info is asked for, show both month and year 98 // If any credit card expiration info is asked for, show both month and year
93 // inputs. 99 // inputs.
94 if (field_type == CREDIT_CARD_EXP_4_DIGIT_YEAR || 100 if (field_type == CREDIT_CARD_EXP_4_DIGIT_YEAR ||
95 field_type == CREDIT_CARD_EXP_2_DIGIT_YEAR || 101 field_type == CREDIT_CARD_EXP_2_DIGIT_YEAR ||
96 field_type == CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR || 102 field_type == CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR ||
97 field_type == CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR || 103 field_type == CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR ||
98 field_type == CREDIT_CARD_EXP_MONTH) { 104 field_type == CREDIT_CARD_EXP_MONTH) {
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 AutofillFieldType type) { 226 AutofillFieldType type) {
221 for (DetailOutputMap::const_iterator it = output.begin(); 227 for (DetailOutputMap::const_iterator it = output.begin();
222 it != output.end(); ++it) { 228 it != output.end(); ++it) {
223 if (it->first->type == type) 229 if (it->first->type == type)
224 return it->second; 230 return it->second;
225 } 231 }
226 NOTREACHED(); 232 NOTREACHED();
227 return string16(); 233 return string16();
228 } 234 }
229 235
236 // Returns a string descriptor for a DialogSection, for use with prefs (do not
237 // change these values).
238 std::string SectionToPrefString(DialogSection section) {
239 switch (section) {
240 case SECTION_CC:
241 return "cc";
242
243 case SECTION_BILLING:
244 return "billing";
245
246 case SECTION_CC_BILLING:
247 // The SECTION_CC_BILLING section isn't active when using Autofill.
248 NOTREACHED();
249 return std::string();
250
251 case SECTION_SHIPPING:
252 return "shipping";
253
254 case SECTION_EMAIL:
255 return "email";
256 }
257
258 NOTREACHED();
259 return std::string();
260 }
261
230 } // namespace 262 } // namespace
231 263
232 AutofillDialogController::~AutofillDialogController() {} 264 AutofillDialogController::~AutofillDialogController() {}
233 265
234 AutofillDialogControllerImpl::~AutofillDialogControllerImpl() { 266 AutofillDialogControllerImpl::~AutofillDialogControllerImpl() {
235 if (popup_controller_) 267 if (popup_controller_)
236 popup_controller_->Hide(); 268 popup_controller_->Hide();
237 269
238 GetMetricLogger().LogDialogInitialUserState( 270 GetMetricLogger().LogDialogInitialUserState(
239 GetDialogType(), initial_user_state_); 271 GetDialogType(), initial_user_state_);
(...skipping 18 matching lines...) Expand all
258 return autofill_dialog_controller->weak_ptr_factory_.GetWeakPtr(); 290 return autofill_dialog_controller->weak_ptr_factory_.GetWeakPtr();
259 } 291 }
260 292
261 // static 293 // static
262 void AutofillDialogControllerImpl::RegisterUserPrefs( 294 void AutofillDialogControllerImpl::RegisterUserPrefs(
263 user_prefs::PrefRegistrySyncable* registry) { 295 user_prefs::PrefRegistrySyncable* registry) {
264 registry->RegisterBooleanPref( 296 registry->RegisterBooleanPref(
265 ::prefs::kAutofillDialogPayWithoutWallet, 297 ::prefs::kAutofillDialogPayWithoutWallet,
266 kPayWithoutWalletDefault, 298 kPayWithoutWalletDefault,
267 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); 299 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
300 registry->RegisterDictionaryPref(
301 ::prefs::kAutofillDialogAutofillDefault,
302 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
268 } 303 }
269 304
270 void AutofillDialogControllerImpl::Show() { 305 void AutofillDialogControllerImpl::Show() {
271 dialog_shown_timestamp_ = base::Time::Now(); 306 dialog_shown_timestamp_ = base::Time::Now();
272 307
273 content::NavigationEntry* entry = contents_->GetController().GetActiveEntry(); 308 content::NavigationEntry* entry = contents_->GetController().GetActiveEntry();
274 const GURL& active_url = entry ? entry->GetURL() : contents_->GetURL(); 309 const GURL& active_url = entry ? entry->GetURL() : contents_->GetURL();
275 invoked_from_same_origin_ = active_url.GetOrigin() == source_url_.GetOrigin(); 310 invoked_from_same_origin_ = active_url.GetOrigin() == source_url_.GetOrigin();
276 311
277 // Log any relevant UI metrics and security exceptions. 312 // Log any relevant UI metrics and security exceptions.
(...skipping 653 matching lines...) Expand 10 before | Expand all | Expand 10 after
931 966
932 return scoped_ptr<DataModelWrapper>(); 967 return scoped_ptr<DataModelWrapper>();
933 } 968 }
934 969
935 if (section == SECTION_CC) { 970 if (section == SECTION_CC) {
936 CreditCard* card = GetManager()->GetCreditCardByGUID(item_key); 971 CreditCard* card = GetManager()->GetCreditCardByGUID(item_key);
937 DCHECK(card); 972 DCHECK(card);
938 return scoped_ptr<DataModelWrapper>(new AutofillCreditCardWrapper(card)); 973 return scoped_ptr<DataModelWrapper>(new AutofillCreditCardWrapper(card));
939 } 974 }
940 975
941 // Calculate the variant by looking at how many items come from the same
942 // data model.
943 size_t variant = 0;
944 for (int i = model->checked_item() - 1; i >= 0; --i) {
945 if (model->GetItemKeyAt(i) == item_key)
946 variant++;
947 else
948 break;
949 }
950
951 AutofillProfile* profile = GetManager()->GetProfileByGUID(item_key); 976 AutofillProfile* profile = GetManager()->GetProfileByGUID(item_key);
952 DCHECK(profile); 977 DCHECK(profile);
978 size_t variant = GetSelectedVariantForModel(*model);
953 return scoped_ptr<DataModelWrapper>( 979 return scoped_ptr<DataModelWrapper>(
954 new AutofillProfileWrapper(profile, variant)); 980 new AutofillProfileWrapper(profile, variant));
955 } 981 }
956 982
957 gfx::Image AutofillDialogControllerImpl::SuggestionIconForSection( 983 gfx::Image AutofillDialogControllerImpl::SuggestionIconForSection(
958 DialogSection section) { 984 DialogSection section) {
959 scoped_ptr<DataModelWrapper> model = CreateWrapper(section); 985 scoped_ptr<DataModelWrapper> model = CreateWrapper(section);
960 if (!model.get()) 986 if (!model.get())
961 return gfx::Image(); 987 return gfx::Image();
962 988
(...skipping 904 matching lines...) Expand 10 before | Expand all | Expand 10 after
1867 } 1893 }
1868 1894
1869 suggested_shipping_.AddKeyedItem( 1895 suggested_shipping_.AddKeyedItem(
1870 kAddNewItemKey, 1896 kAddNewItemKey,
1871 l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_SHIPPING_ADDRESS)); 1897 l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_SHIPPING_ADDRESS));
1872 suggested_shipping_.AddKeyedItem( 1898 suggested_shipping_.AddKeyedItem(
1873 kManageItemsKey, 1899 kManageItemsKey,
1874 l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_MANAGE_SHIPPING_ADDRESS)); 1900 l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_MANAGE_SHIPPING_ADDRESS));
1875 1901
1876 if (!IsPayingWithWallet()) { 1902 if (!IsPayingWithWallet()) {
1877 // When using Autofill, the default option is the first suggestion, if 1903 for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
1878 // one exists. Otherwise it's the "Use shipping for billing" item. 1904 DialogSection section = static_cast<DialogSection>(i);
1879 const std::string& first_real_suggestion_item_key = 1905 if (!SectionIsActive(section))
1880 suggested_shipping_.GetItemKeyAt(1); 1906 continue;
1881 if (IsASuggestionItemKey(first_real_suggestion_item_key)) 1907
1882 suggested_shipping_.SetCheckedItem(first_real_suggestion_item_key); 1908 // Set the starting choice for the menu. First set to the default in case
1909 // the GUID saved in prefs refers to a profile that no longer exists.
1910 std::string guid;
1911 int variant;
1912 GetDefaultAutofillChoice(section, &guid, &variant);
1913 SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
1914 model->SetCheckedItemNthWithKey(guid, variant + 1);
1915 if (GetAutofillChoice(section, &guid, &variant))
1916 model->SetCheckedItemNthWithKey(guid, variant + 1);
1917 }
1883 } 1918 }
1884 1919
1885 if (view_) 1920 if (view_)
1886 view_->ModelChanged(); 1921 view_->ModelChanged();
1887 1922
1888 for (size_t section = SECTION_MIN; section <= SECTION_MAX; ++section) { 1923 for (size_t section = SECTION_MIN; section <= SECTION_MAX; ++section) {
1889 PrepareDetailInputsForSection(static_cast<DialogSection>(section)); 1924 PrepareDetailInputsForSection(static_cast<DialogSection>(section));
1890 } 1925 }
1891 } 1926 }
1892 1927
(...skipping 508 matching lines...) Expand 10 before | Expand all | Expand 10 after
2401 FillOutputForSectionWithComparator( 2436 FillOutputForSectionWithComparator(
2402 SECTION_CC, 2437 SECTION_CC,
2403 base::Bind(DetailInputMatchesShippingField)); 2438 base::Bind(DetailInputMatchesShippingField));
2404 FillOutputForSectionWithComparator( 2439 FillOutputForSectionWithComparator(
2405 SECTION_CC_BILLING, 2440 SECTION_CC_BILLING,
2406 base::Bind(DetailInputMatchesShippingField)); 2441 base::Bind(DetailInputMatchesShippingField));
2407 } else { 2442 } else {
2408 FillOutputForSection(SECTION_SHIPPING); 2443 FillOutputForSection(SECTION_SHIPPING);
2409 } 2444 }
2410 2445
2446 if (!IsPayingWithWallet()) {
2447 for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
2448 DialogSection section = static_cast<DialogSection>(i);
2449 if (!SectionIsActive(section))
2450 continue;
2451
2452 SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
2453 std::string item_key = model->GetItemKeyForCheckedItem();
2454 if (IsASuggestionItemKey(item_key) || item_key == kSameAsBillingKey) {
2455 int variant = GetSelectedVariantForModel(*model);
2456 PersistAutofillChoice(section, item_key, variant);
2457 }
2458 }
2459 }
2460
2411 callback_.Run(&form_structure_, !wallet_items_ ? std::string() : 2461 callback_.Run(&form_structure_, !wallet_items_ ? std::string() :
2412 wallet_items_->google_transaction_id()); 2462 wallet_items_->google_transaction_id());
2413 callback_ = base::Callback<void(const FormStructure*, const std::string&)>(); 2463 callback_ = base::Callback<void(const FormStructure*, const std::string&)>();
2414 2464
2415 LogOnFinishSubmitMetrics(); 2465 LogOnFinishSubmitMetrics();
2416 2466
2417 // On a successful submit, if the user manually selected "pay without wallet", 2467 // On a successful submit, if the user manually selected "pay without wallet",
2418 // stop trying to pay with Wallet on future runs of the dialog. 2468 // stop trying to pay with Wallet on future runs of the dialog.
2419 bool manually_selected_pay_without_wallet = 2469 bool manually_selected_pay_without_wallet =
2420 !account_chooser_model_.WalletIsSelected() && 2470 !account_chooser_model_.WalletIsSelected() &&
(...skipping 14 matching lines...) Expand all
2435 view_->UpdateNotificationArea(); 2485 view_->UpdateNotificationArea();
2436 break; 2486 break;
2437 2487
2438 case DIALOG_TYPE_REQUEST_AUTOCOMPLETE: 2488 case DIALOG_TYPE_REQUEST_AUTOCOMPLETE:
2439 // This may delete us. 2489 // This may delete us.
2440 Hide(); 2490 Hide();
2441 break; 2491 break;
2442 } 2492 }
2443 } 2493 }
2444 2494
2495 void AutofillDialogControllerImpl::PersistAutofillChoice(
2496 DialogSection section,
2497 const std::string& guid,
2498 int variant) {
2499 DCHECK(!IsPayingWithWallet());
2500 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
2501 value->SetString(kGuidPrefKey, guid);
2502 value->SetInteger(kVariantPrefKey, variant);
2503
2504 DictionaryPrefUpdate updater(profile()->GetPrefs(),
2505 ::prefs::kAutofillDialogAutofillDefault);
2506 base::DictionaryValue* autofill_choice = updater.Get();
2507 autofill_choice->Set(SectionToPrefString(section), value.release());
2508 }
2509
2510 void AutofillDialogControllerImpl::GetDefaultAutofillChoice(
2511 DialogSection section,
2512 std::string* guid,
2513 int* variant) {
2514 DCHECK(!IsPayingWithWallet());
2515 // The default choice is the first thing in the menu that is a suggestion
2516 // item.
2517 *variant = 0;
2518 SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
2519 for (int i = 0; i < model->GetItemCount(); ++i) {
2520 if (IsASuggestionItemKey(model->GetItemKeyAt(i))) {
2521 *guid = model->GetItemKeyAt(i);
2522 break;
2523 }
2524 }
2525 }
2526
2527 bool AutofillDialogControllerImpl::GetAutofillChoice(DialogSection section,
2528 std::string* guid,
2529 int* variant) {
2530 DCHECK(!IsPayingWithWallet());
2531 const base::DictionaryValue* choices = profile()->GetPrefs()->GetDictionary(
2532 ::prefs::kAutofillDialogAutofillDefault);
2533 if (!choices)
2534 return false;
2535
2536 const base::DictionaryValue* choice = NULL;
2537 if (!choices->GetDictionary(SectionToPrefString(section), &choice))
2538 return false;
2539
2540 choice->GetString(kGuidPrefKey, guid);
2541 choice->GetInteger(kVariantPrefKey, variant);
2542 return true;
2543 }
2544
2545 size_t AutofillDialogControllerImpl::GetSelectedVariantForModel(
2546 const SuggestionsMenuModel& model) {
2547 size_t variant = 0;
2548 // Calculate the variant by looking at how many items come from the same
2549 // data model.
2550 for (int i = model.checked_item() - 1; i >= 0; --i) {
2551 if (model.GetItemKeyAt(i) == model.GetItemKeyForCheckedItem())
2552 variant++;
2553 else
2554 break;
2555 }
2556 return variant;
2557 }
2558
2445 void AutofillDialogControllerImpl::LogOnFinishSubmitMetrics() { 2559 void AutofillDialogControllerImpl::LogOnFinishSubmitMetrics() {
2446 GetMetricLogger().LogDialogUiDuration( 2560 GetMetricLogger().LogDialogUiDuration(
2447 base::Time::Now() - dialog_shown_timestamp_, 2561 base::Time::Now() - dialog_shown_timestamp_,
2448 GetDialogType(), 2562 GetDialogType(),
2449 AutofillMetrics::DIALOG_ACCEPTED); 2563 AutofillMetrics::DIALOG_ACCEPTED);
2450 2564
2451 GetMetricLogger().LogDialogUiEvent( 2565 GetMetricLogger().LogDialogUiEvent(
2452 GetDialogType(), AutofillMetrics::DIALOG_UI_ACCEPTED); 2566 GetDialogType(), AutofillMetrics::DIALOG_UI_ACCEPTED);
2453 2567
2454 AutofillMetrics::DialogDismissalState dismissal_state; 2568 AutofillMetrics::DialogDismissalState dismissal_state;
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
2538 AutofillMetrics::DIALOG_USER_SIGNED_IN_NO_WALLET_NO_AUTOFILL; 2652 AutofillMetrics::DIALOG_USER_SIGNED_IN_NO_WALLET_NO_AUTOFILL;
2539 } 2653 }
2540 2654
2541 // Has Wallet items. 2655 // Has Wallet items.
2542 return has_autofill_profiles ? 2656 return has_autofill_profiles ?
2543 AutofillMetrics::DIALOG_USER_SIGNED_IN_HAS_WALLET_HAS_AUTOFILL : 2657 AutofillMetrics::DIALOG_USER_SIGNED_IN_HAS_WALLET_HAS_AUTOFILL :
2544 AutofillMetrics::DIALOG_USER_SIGNED_IN_HAS_WALLET_NO_AUTOFILL; 2658 AutofillMetrics::DIALOG_USER_SIGNED_IN_HAS_WALLET_NO_AUTOFILL;
2545 } 2659 }
2546 2660
2547 } // namespace autofill 2661 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698