| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/save_card_bubble_controller_impl.h" | 5 #include "chrome/browser/ui/autofill/save_card_bubble_controller_impl.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include "base/i18n/message_formatter.h" | |
| 10 #include "base/strings/string_util.h" | |
| 11 #include "base/strings/utf_string_conversions.h" | |
| 12 #include "chrome/browser/ui/autofill/save_card_bubble_view.h" | 9 #include "chrome/browser/ui/autofill/save_card_bubble_view.h" |
| 13 #include "chrome/browser/ui/browser.h" | 10 #include "chrome/browser/ui/browser.h" |
| 14 #include "chrome/browser/ui/browser_finder.h" | 11 #include "chrome/browser/ui/browser_finder.h" |
| 15 #include "chrome/browser/ui/browser_window.h" | 12 #include "chrome/browser/ui/browser_window.h" |
| 16 #include "chrome/browser/ui/location_bar/location_bar.h" | 13 #include "chrome/browser/ui/location_bar/location_bar.h" |
| 17 #include "components/autofill/core/browser/autofill_metrics.h" | 14 #include "components/autofill/core/browser/autofill_metrics.h" |
| 18 #include "components/autofill/core/common/autofill_constants.h" | 15 #include "components/autofill/core/common/autofill_constants.h" |
| 19 #include "content/public/browser/navigation_details.h" | 16 #include "content/public/browser/navigation_details.h" |
| 20 #include "grit/components_strings.h" | 17 #include "grit/components_strings.h" |
| 21 #include "ui/base/l10n/l10n_util.h" | 18 #include "ui/base/l10n/l10n_util.h" |
| 22 | 19 |
| 23 DEFINE_WEB_CONTENTS_USER_DATA_KEY(autofill::SaveCardBubbleControllerImpl); | 20 DEFINE_WEB_CONTENTS_USER_DATA_KEY(autofill::SaveCardBubbleControllerImpl); |
| 24 | 21 |
| 25 namespace autofill { | 22 namespace autofill { |
| 26 | 23 |
| 27 namespace { | 24 namespace { |
| 28 | 25 |
| 29 // Number of seconds the bubble and icon will survive navigations, starting | 26 // Number of seconds the bubble and icon will survive navigations, starting |
| 30 // from when the bubble is shown. | 27 // from when the bubble is shown. |
| 31 // TODO(bondd): Share with ManagePasswordsUIController. | 28 // TODO(bondd): Share with ManagePasswordsUIController. |
| 32 const int kSurviveNavigationSeconds = 5; | 29 const int kSurviveNavigationSeconds = 5; |
| 33 | 30 |
| 34 // Replace "{0}", "{1}", ... in |template_icu| with corresponding strings | |
| 35 // from |display_texts|. Sets |out_message| to the resulting string, with | |
| 36 // start position of each replacement in |out_offsets|. | |
| 37 // Return false on failure. If false is returned then contents of |out_message| | |
| 38 // and |out_offsets| are undefined. | |
| 39 bool ReplaceTemplatePlaceholders( | |
| 40 const base::string16& template_icu, | |
| 41 const std::vector<base::string16>& display_texts, | |
| 42 base::string16* out_message, | |
| 43 std::vector<size_t>* out_offsets) { | |
| 44 // Escape "$" -> "$$" for ReplaceStringPlaceholders(). | |
| 45 // | |
| 46 // Edge cases: | |
| 47 // 1. Two or more consecutive $ characters will be incorrectly expanded | |
| 48 // ("$$" -> "$$$$", which ReplaceStringPlaceholders() then turns into | |
| 49 // "$$$"). | |
| 50 // | |
| 51 // 2. "${" will cause false to be returned. "${0}" will expand to "$${0}". | |
| 52 // FormatWithNumberedArgs() turns it into "$$$1", which | |
| 53 // ReplaceStringPlaceholders() then turns into "$$1" without doing the | |
| 54 // parameter replacement. This causes false to be returned because each | |
| 55 // parameter is not used exactly once. | |
| 56 // | |
| 57 // Both of these cases are noted in the header file, and are unlikely to | |
| 58 // occur in any actual legal message. | |
| 59 base::string16 template_icu_escaped; | |
| 60 base::ReplaceChars(template_icu, base::ASCIIToUTF16("$"), | |
| 61 base::ASCIIToUTF16("$$"), &template_icu_escaped); | |
| 62 | |
| 63 // Replace "{0}" -> "$1", "{1}" -> "$2", ... to prepare |template_dollars| | |
| 64 // for ReplaceStringPlaceholders(). | |
| 65 base::string16 template_dollars = | |
| 66 base::i18n::MessageFormatter::FormatWithNumberedArgs( | |
| 67 template_icu_escaped, "$1", "$2", "$3", "$4", "$5", "$6", "$7"); | |
| 68 | |
| 69 // FormatWithNumberedArgs() returns an empty string on failure. | |
| 70 if (template_dollars.empty() && !template_icu.empty()) | |
| 71 return false; | |
| 72 | |
| 73 // Replace "$1", "$2", ... with the display text of each parameter. | |
| 74 *out_message = base::ReplaceStringPlaceholders(template_dollars, | |
| 75 display_texts, out_offsets); | |
| 76 | |
| 77 // Each parameter must be used exactly once. If a parameter is unused or | |
| 78 // used more than once then it can't be determined which |offsets| entry | |
| 79 // corresponds to which parameter. | |
| 80 return out_offsets->size() == display_texts.size(); | |
| 81 } | |
| 82 | |
| 83 // Parses |line| and sets |out|. | |
| 84 // Returns false on failure. |out| is not modified if false is returned. | |
| 85 bool ParseLegalMessageLine(const base::DictionaryValue& line, | |
| 86 SaveCardBubbleController::LegalMessageLine* out) { | |
| 87 SaveCardBubbleController::LegalMessageLine result; | |
| 88 | |
| 89 // |display_texts| elements are the strings that will be substituted for | |
| 90 // "{0}", "{1}", etc. in the template string. | |
| 91 std::vector<base::string16> display_texts; | |
| 92 | |
| 93 // Process all the template parameters. | |
| 94 const base::ListValue* template_parameters = nullptr; | |
| 95 if (line.GetList("template_parameter", &template_parameters)) { | |
| 96 display_texts.resize(template_parameters->GetSize()); | |
| 97 result.links.resize(template_parameters->GetSize()); | |
| 98 | |
| 99 for (size_t parameter_index = 0; | |
| 100 parameter_index < template_parameters->GetSize(); ++parameter_index) { | |
| 101 const base::DictionaryValue* single_parameter; | |
| 102 std::string url; | |
| 103 if (!template_parameters->GetDictionary(parameter_index, | |
| 104 &single_parameter) || | |
| 105 !single_parameter->GetString("display_text", | |
| 106 &display_texts[parameter_index]) || | |
| 107 !single_parameter->GetString("url", &url)) { | |
| 108 return false; | |
| 109 } | |
| 110 result.links[parameter_index].url = GURL(url); | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 // Read the template string. It's a small subset of the ICU message format | |
| 115 // syntax. | |
| 116 base::string16 template_icu; | |
| 117 if (!line.GetString("template", &template_icu)) | |
| 118 return false; | |
| 119 | |
| 120 // Replace the placeholders in |template_icu| with strings from | |
| 121 // |display_texts|, and store the start position of each replacement in | |
| 122 // |offsets|. | |
| 123 std::vector<size_t> offsets; | |
| 124 if (!ReplaceTemplatePlaceholders(template_icu, display_texts, &result.text, | |
| 125 &offsets)) { | |
| 126 return false; | |
| 127 } | |
| 128 | |
| 129 // Fill in range values for all links. | |
| 130 for (size_t offset_index = 0; offset_index < offsets.size(); ++offset_index) { | |
| 131 size_t range_start = offsets[offset_index]; | |
| 132 result.links[offset_index].range = gfx::Range( | |
| 133 range_start, range_start + display_texts[offset_index].size()); | |
| 134 } | |
| 135 | |
| 136 *out = result; | |
| 137 return true; | |
| 138 } | |
| 139 | |
| 140 } // namespace | 31 } // namespace |
| 141 | 32 |
| 142 SaveCardBubbleControllerImpl::SaveCardBubbleControllerImpl( | 33 SaveCardBubbleControllerImpl::SaveCardBubbleControllerImpl( |
| 143 content::WebContents* web_contents) | 34 content::WebContents* web_contents) |
| 144 : content::WebContentsObserver(web_contents), | 35 : content::WebContentsObserver(web_contents), |
| 145 save_card_bubble_view_(nullptr) { | 36 save_card_bubble_view_(nullptr) { |
| 146 DCHECK(web_contents); | 37 DCHECK(web_contents); |
| 147 } | 38 } |
| 148 | 39 |
| 149 SaveCardBubbleControllerImpl::~SaveCardBubbleControllerImpl() { | 40 SaveCardBubbleControllerImpl::~SaveCardBubbleControllerImpl() { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 165 | 56 |
| 166 void SaveCardBubbleControllerImpl::ShowBubbleForUpload( | 57 void SaveCardBubbleControllerImpl::ShowBubbleForUpload( |
| 167 const base::Closure& save_card_callback, | 58 const base::Closure& save_card_callback, |
| 168 scoped_ptr<base::DictionaryValue> legal_message) { | 59 scoped_ptr<base::DictionaryValue> legal_message) { |
| 169 is_uploading_ = true; | 60 is_uploading_ = true; |
| 170 is_reshow_ = false; | 61 is_reshow_ = false; |
| 171 AutofillMetrics::LogSaveCardPromptMetric( | 62 AutofillMetrics::LogSaveCardPromptMetric( |
| 172 AutofillMetrics::SAVE_CARD_PROMPT_SHOW_REQUESTED, is_uploading_, | 63 AutofillMetrics::SAVE_CARD_PROMPT_SHOW_REQUESTED, is_uploading_, |
| 173 is_reshow_); | 64 is_reshow_); |
| 174 | 65 |
| 175 const base::ListValue* lines = nullptr; | 66 if (!LegalMessageLine::Parse(*legal_message, &legal_message_lines_)) { |
| 176 if (legal_message->GetList("line", &lines)) { | |
| 177 // Process all lines of the legal message. See comment in header file for | |
| 178 // example of valid |legal_message| data. | |
| 179 legal_message_lines_.resize(lines->GetSize()); | |
| 180 for (size_t i = 0; i < lines->GetSize(); ++i) { | |
| 181 const base::DictionaryValue* single_line; | |
| 182 if (!lines->GetDictionary(i, &single_line) || | |
| 183 !ParseLegalMessageLine(*single_line, &legal_message_lines_[i])) { | |
| 184 lines = nullptr; | |
| 185 break; | |
| 186 } | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 if (!lines) { | |
| 191 AutofillMetrics::LogSaveCardPromptMetric( | 67 AutofillMetrics::LogSaveCardPromptMetric( |
| 192 AutofillMetrics::SAVE_CARD_PROMPT_END_INVALID_LEGAL_MESSAGE, | 68 AutofillMetrics::SAVE_CARD_PROMPT_END_INVALID_LEGAL_MESSAGE, |
| 193 is_uploading_, is_reshow_); | 69 is_uploading_, is_reshow_); |
| 194 | |
| 195 legal_message_lines_.clear(); | |
| 196 return; | 70 return; |
| 197 } | 71 } |
| 198 | 72 |
| 199 save_card_callback_ = save_card_callback; | 73 save_card_callback_ = save_card_callback; |
| 200 ShowBubble(); | 74 ShowBubble(); |
| 201 } | 75 } |
| 202 | 76 |
| 203 void SaveCardBubbleControllerImpl::ReshowBubble() { | 77 void SaveCardBubbleControllerImpl::ReshowBubble() { |
| 204 is_reshow_ = true; | 78 is_reshow_ = true; |
| 205 AutofillMetrics::LogSaveCardPromptMetric( | 79 AutofillMetrics::LogSaveCardPromptMetric( |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 AutofillMetrics::LogSaveCardPromptMetric( | 130 AutofillMetrics::LogSaveCardPromptMetric( |
| 257 AutofillMetrics::SAVE_CARD_PROMPT_DISMISS_CLICK_LEGAL_MESSAGE, | 131 AutofillMetrics::SAVE_CARD_PROMPT_DISMISS_CLICK_LEGAL_MESSAGE, |
| 258 is_uploading_, is_reshow_); | 132 is_uploading_, is_reshow_); |
| 259 } | 133 } |
| 260 | 134 |
| 261 void SaveCardBubbleControllerImpl::OnBubbleClosed() { | 135 void SaveCardBubbleControllerImpl::OnBubbleClosed() { |
| 262 save_card_bubble_view_ = nullptr; | 136 save_card_bubble_view_ = nullptr; |
| 263 UpdateIcon(); | 137 UpdateIcon(); |
| 264 } | 138 } |
| 265 | 139 |
| 266 const SaveCardBubbleController::LegalMessageLines& | 140 const LegalMessageLines& SaveCardBubbleControllerImpl::GetLegalMessageLines() |
| 267 SaveCardBubbleControllerImpl::GetLegalMessageLines() const { | 141 const { |
| 268 return legal_message_lines_; | 142 return legal_message_lines_; |
| 269 } | 143 } |
| 270 | 144 |
| 271 base::TimeDelta SaveCardBubbleControllerImpl::Elapsed() const { | 145 base::TimeDelta SaveCardBubbleControllerImpl::Elapsed() const { |
| 272 return timer_->Elapsed(); | 146 return timer_->Elapsed(); |
| 273 } | 147 } |
| 274 | 148 |
| 275 void SaveCardBubbleControllerImpl::DidNavigateMainFrame( | 149 void SaveCardBubbleControllerImpl::DidNavigateMainFrame( |
| 276 const content::LoadCommittedDetails& details, | 150 const content::LoadCommittedDetails& details, |
| 277 const content::FrameNavigateParams& params) { | 151 const content::FrameNavigateParams& params) { |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 location_bar->UpdateSaveCreditCardIcon(); | 209 location_bar->UpdateSaveCreditCardIcon(); |
| 336 } | 210 } |
| 337 | 211 |
| 338 void SaveCardBubbleControllerImpl::OpenUrl(const GURL& url) { | 212 void SaveCardBubbleControllerImpl::OpenUrl(const GURL& url) { |
| 339 web_contents()->OpenURL( | 213 web_contents()->OpenURL( |
| 340 content::OpenURLParams(url, content::Referrer(), NEW_FOREGROUND_TAB, | 214 content::OpenURLParams(url, content::Referrer(), NEW_FOREGROUND_TAB, |
| 341 ui::PAGE_TRANSITION_LINK, false)); | 215 ui::PAGE_TRANSITION_LINK, false)); |
| 342 } | 216 } |
| 343 | 217 |
| 344 } // namespace autofill | 218 } // namespace autofill |
| OLD | NEW |