| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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 // The |FeedbackSender| object stores the user feedback to spellcheck | 5 // The |FeedbackSender| object stores the user feedback to spellcheck |
| 6 // suggestions in a |Feedback| object. | 6 // suggestions in a |Feedback| object. |
| 7 // | 7 // |
| 8 // When spelling service returns spellcheck results, these results first arrive | 8 // When spelling service returns spellcheck results, these results first arrive |
| 9 // in |FeedbackSender| to assign hash identifiers for each | 9 // in |FeedbackSender| to assign hash identifiers for each |
| 10 // misspelling-suggestion pair. If the spelling service identifies the same | 10 // misspelling-suggestion pair. If the spelling service identifies the same |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 params->Set("suggestionInfo", suggestion_info); | 113 params->Set("suggestionInfo", suggestion_info); |
| 114 params->SetString("key", google_apis::GetAPIKey()); | 114 params->SetString("key", google_apis::GetAPIKey()); |
| 115 params->SetString("language", language); | 115 params->SetString("language", language); |
| 116 params->SetString("originCountry", country); | 116 params->SetString("originCountry", country); |
| 117 params->SetString("clientName", "Chrome"); | 117 params->SetString("clientName", "Chrome"); |
| 118 return params; | 118 return params; |
| 119 } | 119 } |
| 120 | 120 |
| 121 // Builds feedback data from |params|. Takes ownership of |params|. The caller | 121 // Builds feedback data from |params|. Takes ownership of |params|. The caller |
| 122 // owns the result. | 122 // owns the result. |
| 123 base::Value* BuildFeedbackValue(base::DictionaryValue* params) { | 123 base::Value* BuildFeedbackValue(base::DictionaryValue* params, |
| 124 const std::string& api_version) { |
| 124 base::DictionaryValue* result = new base::DictionaryValue; | 125 base::DictionaryValue* result = new base::DictionaryValue; |
| 125 result->Set("params", params); | 126 result->Set("params", params); |
| 126 result->SetString("method", "spelling.feedback"); | 127 result->SetString("method", "spelling.feedback"); |
| 127 result->SetString("apiVersion", "v2"); | 128 result->SetString("apiVersion", api_version); |
| 128 return result; | 129 return result; |
| 129 } | 130 } |
| 130 | 131 |
| 131 // Returns true if the misspelling location is within text bounds. | 132 // Returns true if the misspelling location is within text bounds. |
| 132 bool IsInBounds(int misspelling_location, | 133 bool IsInBounds(int misspelling_location, |
| 133 int misspelling_length, | 134 int misspelling_length, |
| 134 size_t text_length) { | 135 size_t text_length) { |
| 135 return misspelling_location >= 0 && misspelling_length > 0 && | 136 return misspelling_location >= 0 && misspelling_length > 0 && |
| 136 static_cast<size_t>(misspelling_location) < text_length && | 137 static_cast<size_t>(misspelling_location) < text_length && |
| 137 static_cast<size_t>(misspelling_location + misspelling_length) <= | 138 static_cast<size_t>(misspelling_location + misspelling_length) <= |
| 138 text_length; | 139 text_length; |
| 139 } | 140 } |
| 140 | 141 |
| 142 // Returns the feedback API version. |
| 143 std::string GetApiVersion() { |
| 144 // This guard is temporary. |
| 145 // TODO(rouslan): Remove the guard. http://crbug.com/247726 |
| 146 if (base::FieldTrialList::FindFullName(kFeedbackFieldTrialName) == |
| 147 kFeedbackFieldTrialEnabledGroupName && |
| 148 CommandLine::ForCurrentProcess()->HasSwitch( |
| 149 switches::kEnableSpellingFeedbackFieldTrial)) { |
| 150 return "v2-internal"; |
| 151 } |
| 152 return "v2"; |
| 153 } |
| 154 |
| 141 } // namespace | 155 } // namespace |
| 142 | 156 |
| 143 FeedbackSender::FeedbackSender(net::URLRequestContextGetter* request_context, | 157 FeedbackSender::FeedbackSender(net::URLRequestContextGetter* request_context, |
| 144 const std::string& language, | 158 const std::string& language, |
| 145 const std::string& country) | 159 const std::string& country) |
| 146 : request_context_(request_context), | 160 : request_context_(request_context), |
| 161 api_version_(GetApiVersion()), |
| 147 language_(language), | 162 language_(language), |
| 148 country_(country), | 163 country_(country), |
| 149 misspelling_counter_(0), | 164 misspelling_counter_(0), |
| 150 session_start_(base::Time::Now()), | 165 session_start_(base::Time::Now()), |
| 151 feedback_service_url_(kFeedbackServiceURL) { | 166 feedback_service_url_(kFeedbackServiceURL) { |
| 152 // This guard is temporary. | |
| 153 // TODO(rouslan): Remove the guard. http://crbug.com/247726 | |
| 154 if (!CommandLine::ForCurrentProcess()->HasSwitch( | |
| 155 switches::kEnableSpellingServiceFeedback) || | |
| 156 base::FieldTrialList::FindFullName(kFeedbackFieldTrialName) != | |
| 157 kFeedbackFieldTrialEnabledGroupName) { | |
| 158 return; | |
| 159 } | |
| 160 | |
| 161 // The command-line switch is for testing and temporary. | 167 // The command-line switch is for testing and temporary. |
| 162 // TODO(rouslan): Remove the command-line switch when testing is complete. | 168 // TODO(rouslan): Remove the command-line switch when testing is complete. |
| 163 // http://crbug.com/247726 | 169 // http://crbug.com/247726 |
| 164 if (CommandLine::ForCurrentProcess()->HasSwitch( | 170 if (CommandLine::ForCurrentProcess()->HasSwitch( |
| 165 switches::kSpellingServiceFeedbackUrl)) { | 171 switches::kSpellingServiceFeedbackUrl)) { |
| 166 feedback_service_url_ = | 172 feedback_service_url_ = |
| 167 GURL(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | 173 GURL(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| 168 switches::kSpellingServiceFeedbackUrl)); | 174 switches::kSpellingServiceFeedbackUrl)); |
| 169 } | 175 } |
| 170 | |
| 171 int interval_seconds = chrome::spellcheck_common::kFeedbackIntervalSeconds; | |
| 172 // This command-line switch is for testing and temporary. | |
| 173 // TODO(rouslan): Remove the command-line switch when testing is complete. | |
| 174 // http://crbug.com/247726 | |
| 175 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
| 176 switches::kSpellingServiceFeedbackIntervalSeconds)) { | |
| 177 base::StringToInt(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
| 178 switches::kSpellingServiceFeedbackIntervalSeconds), | |
| 179 &interval_seconds); | |
| 180 if (interval_seconds < kMinIntervalSeconds) | |
| 181 interval_seconds = kMinIntervalSeconds; | |
| 182 } | |
| 183 | |
| 184 timer_.Start(FROM_HERE, | |
| 185 base::TimeDelta::FromSeconds(interval_seconds), | |
| 186 this, | |
| 187 &FeedbackSender::RequestDocumentMarkers); | |
| 188 } | 176 } |
| 189 | 177 |
| 190 FeedbackSender::~FeedbackSender() { | 178 FeedbackSender::~FeedbackSender() { |
| 191 } | 179 } |
| 192 | 180 |
| 193 void FeedbackSender::SelectedSuggestion(uint32 hash, int suggestion_index) { | 181 void FeedbackSender::SelectedSuggestion(uint32 hash, int suggestion_index) { |
| 194 Misspelling* misspelling = feedback_.GetMisspelling(hash); | 182 Misspelling* misspelling = feedback_.GetMisspelling(hash); |
| 195 // GetMisspelling() returns null for flushed feedback. Feedback is flushed | 183 // GetMisspelling() returns null for flushed feedback. Feedback is flushed |
| 196 // when the session expires every |kSessionHours| hours. | 184 // when the session expires every |kSessionHours| hours. |
| 197 if (!misspelling) | 185 if (!misspelling) |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 311 } | 299 } |
| 312 } | 300 } |
| 313 | 301 |
| 314 void FeedbackSender::OnLanguageCountryChange(const std::string& language, | 302 void FeedbackSender::OnLanguageCountryChange(const std::string& language, |
| 315 const std::string& country) { | 303 const std::string& country) { |
| 316 FlushFeedback(); | 304 FlushFeedback(); |
| 317 language_ = language; | 305 language_ = language; |
| 318 country_ = country; | 306 country_ = country; |
| 319 } | 307 } |
| 320 | 308 |
| 309 void FeedbackSender::StartFeedbackCollection() { |
| 310 if (timer_.IsRunning()) |
| 311 return; |
| 312 |
| 313 int interval_seconds = chrome::spellcheck_common::kFeedbackIntervalSeconds; |
| 314 // This command-line switch is for testing and temporary. |
| 315 // TODO(rouslan): Remove the command-line switch when testing is complete. |
| 316 // http://crbug.com/247726 |
| 317 if (CommandLine::ForCurrentProcess()->HasSwitch( |
| 318 switches::kSpellingServiceFeedbackIntervalSeconds)) { |
| 319 base::StringToInt(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| 320 switches::kSpellingServiceFeedbackIntervalSeconds), |
| 321 &interval_seconds); |
| 322 if (interval_seconds < kMinIntervalSeconds) |
| 323 interval_seconds = kMinIntervalSeconds; |
| 324 static const int kSessionSeconds = |
| 325 chrome::spellcheck_common::kSessionHours * 60 * 60; |
| 326 if (interval_seconds > kSessionSeconds) |
| 327 interval_seconds = kSessionSeconds; |
| 328 } |
| 329 timer_.Start(FROM_HERE, |
| 330 base::TimeDelta::FromSeconds(interval_seconds), |
| 331 this, |
| 332 &FeedbackSender::RequestDocumentMarkers); |
| 333 } |
| 334 |
| 335 void FeedbackSender::StopFeedbackCollection() { |
| 336 if (!timer_.IsRunning()) |
| 337 return; |
| 338 |
| 339 FlushFeedback(); |
| 340 timer_.Stop(); |
| 341 } |
| 342 |
| 321 void FeedbackSender::OnURLFetchComplete(const net::URLFetcher* source) { | 343 void FeedbackSender::OnURLFetchComplete(const net::URLFetcher* source) { |
| 322 for (ScopedVector<net::URLFetcher>::iterator sender_it = senders_.begin(); | 344 for (ScopedVector<net::URLFetcher>::iterator sender_it = senders_.begin(); |
| 323 sender_it != senders_.end(); | 345 sender_it != senders_.end(); |
| 324 ++sender_it) { | 346 ++sender_it) { |
| 325 if (*sender_it == source) { | 347 if (*sender_it == source) { |
| 326 senders_.erase(sender_it); | 348 senders_.erase(sender_it); |
| 327 return; | 349 return; |
| 328 } | 350 } |
| 329 } | 351 } |
| 330 delete source; | 352 delete source; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 370 renderers_sent_feedback_.clear(); | 392 renderers_sent_feedback_.clear(); |
| 371 session_start_ = base::Time::Now(); | 393 session_start_ = base::Time::Now(); |
| 372 timer_.Reset(); | 394 timer_.Reset(); |
| 373 } | 395 } |
| 374 | 396 |
| 375 void FeedbackSender::SendFeedback(const std::vector<Misspelling>& feedback_data, | 397 void FeedbackSender::SendFeedback(const std::vector<Misspelling>& feedback_data, |
| 376 bool is_first_feedback_batch) { | 398 bool is_first_feedback_batch) { |
| 377 scoped_ptr<base::Value> feedback_value(BuildFeedbackValue( | 399 scoped_ptr<base::Value> feedback_value(BuildFeedbackValue( |
| 378 BuildParams(BuildSuggestionInfo(feedback_data, is_first_feedback_batch), | 400 BuildParams(BuildSuggestionInfo(feedback_data, is_first_feedback_batch), |
| 379 language_, | 401 language_, |
| 380 country_))); | 402 country_), |
| 403 api_version_)); |
| 381 std::string feedback; | 404 std::string feedback; |
| 382 base::JSONWriter::Write(feedback_value.get(), &feedback); | 405 base::JSONWriter::Write(feedback_value.get(), &feedback); |
| 383 | 406 |
| 384 // The tests use this identifier to mock the URL fetcher. | 407 // The tests use this identifier to mock the URL fetcher. |
| 385 static const int kUrlFetcherId = 0; | 408 static const int kUrlFetcherId = 0; |
| 386 net::URLFetcher* sender = net::URLFetcher::Create( | 409 net::URLFetcher* sender = net::URLFetcher::Create( |
| 387 kUrlFetcherId, feedback_service_url_, net::URLFetcher::POST, this); | 410 kUrlFetcherId, feedback_service_url_, net::URLFetcher::POST, this); |
| 388 sender->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 411 sender->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 389 net::LOAD_DO_NOT_SAVE_COOKIES); | 412 net::LOAD_DO_NOT_SAVE_COOKIES); |
| 390 sender->SetUploadData("application/json", feedback); | 413 sender->SetUploadData("application/json", feedback); |
| 391 senders_.push_back(sender); | 414 senders_.push_back(sender); |
| 392 | 415 |
| 393 // Request context is NULL in testing. | 416 // Request context is NULL in testing. |
| 394 if (request_context_.get()) { | 417 if (request_context_.get()) { |
| 395 sender->SetRequestContext(request_context_.get()); | 418 sender->SetRequestContext(request_context_.get()); |
| 396 sender->Start(); | 419 sender->Start(); |
| 397 } | 420 } |
| 398 } | 421 } |
| 399 | 422 |
| 400 } // namespace spellcheck | 423 } // namespace spellcheck |
| OLD | NEW |