OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |