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
3// found in the LICENSE file.
4//
5// An object to record and send user feedback to spelling service. The spelling
6// service uses the feedback to improve its suggestions.
7//
8// Assigns uint32 hash identifiers to spelling suggestions from spelling service
9// and stores these suggestions. Records user's actions on these suggestions.
10// Periodically sends batches of user feedback to the spelling service.
11
12#ifndef CHROME_BROWSER_SPELLCHECKER_FEEDBACK_SENDER_H_
13#define CHROME_BROWSER_SPELLCHECKER_FEEDBACK_SENDER_H_
14
15#include <map>
16#include <set>
17#include <vector>
18
19#include "base/memory/scoped_vector.h"
20#include "base/memory/weak_ptr.h"
21#include "base/timer/timer.h"
22#include "chrome/browser/spellchecker/feedback.h"
23#include "chrome/browser/spellchecker/misspelling.h"
24#include "net/url_request/url_fetcher_delegate.h"
25#include "url/gurl.h"
26
27class SpellCheckMarker;
28struct SpellCheckResult;
29
30namespace net {
31class URLFetcher;
32class URLRequestContextGetter;
33}
34
35namespace spellcheck {
36
37namespace {
38
39// Constants for the feedback field trial.
40const char kFeedbackFieldTrialName[] = "SpellingServiceFeedback";
41const char kFeedbackFieldTrialEnabledGroupName[] = "Enabled";
42
43}  // namespace
44
45// Stores and sends user feedback to the spelling service. Sample usage:
46//    FeedbackSender sender(profile.GetRequestContext(), language, country);
47//    sender.OnSpellcheckResults(spellcheck_results_from_spelling_service,
48//                               renderer_process_id,
49//                               spellchecked_text,
50//                               existing_hashes);
51//    sender.SelectedSuggestion(hash, suggestion_index);
52class FeedbackSender : public base::SupportsWeakPtr<FeedbackSender>,
53                       public net::URLFetcherDelegate {
54 public:
55  // Constructs a feedback sender. Keeps |request_context| in a scoped_refptr,
56  // because URLRequestContextGetter implements RefcountedThreadSafe.
57  FeedbackSender(net::URLRequestContextGetter* request_context,
58                 const std::string& language,
59                 const std::string& country);
60  virtual ~FeedbackSender();
61
62  // Records that user selected suggestion |suggestion_index| for the
63  // misspelling identified by |hash|.
64  void SelectedSuggestion(uint32 hash, int suggestion_index);
65
66  // Records that user added the misspelling identified by |hash| to the
67  // dictionary.
68  void AddedToDictionary(uint32 hash);
69
70  // Records that user right-clicked on the misspelling identified by |hash|,
71  // but did not select any suggestion.
72  void IgnoredSuggestions(uint32 hash);
73
74  // Records that user did not choose any suggestion but manually corrected the
75  // misspelling identified by |hash| to string |correction|, which is not in
76  // the list of suggestions.
77  void ManuallyCorrected(uint32 hash, const base::string16& correction);
78
79  // Records that user has the misspelling in the custom dictionary. The user
80  // will never see the spellcheck suggestions for the misspelling.
81  void RecordInDictionary(uint32 hash);
82
83  // Receives document markers for renderer with process ID |render_process_id|
84  // when the renderer responds to a RequestDocumentMarkers() call. Finalizes
85  // feedback for the markers that are gone from the renderer. Sends feedback
86  // data for the renderer with process ID |renderer_process_id| to the spelling
87  // service. If the current session has expired, then refreshes the session
88  // start timestamp and sends out all of the feedback data.
89  void OnReceiveDocumentMarkers(int renderer_process_id,
90                                const std::vector<uint32>& markers);
91
92  // Generates feedback data based on spellcheck results. The new feedback data
93  // is pending. Sets hash identifiers for |results|. Called when spelling
94  // service client receives results from the spelling service. Does not take
95  // ownership of |results|.
96  void OnSpellcheckResults(int renderer_process_id,
97                           const base::string16& text,
98                           const std::vector<SpellCheckMarker>& markers,
99                           std::vector<SpellCheckResult>* results);
100
101  // Receives updated language and country code for feedback. Finalizes and
102  // sends out all of the feedback data.
103  void OnLanguageCountryChange(const std::string& language,
104                               const std::string& country);
105
106  // Starts collecting feedback, if it's not already being collected.
107  void StartFeedbackCollection();
108
109  // Sends out all previously collected data and stops collecting feedback, if
110  // it was being collected.
111  void StopFeedbackCollection();
112
113 private:
114  friend class FeedbackSenderTest;
115
116  // net::URLFetcherDelegate implementation. Takes ownership of |source|.
117  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
118
119  // Requests the document markers from all of the renderers to determine which
120  // feedback can be finalized. Finalizes feedback for renderers that are gone.
121  // Called periodically when |timer_| fires.
122  void RequestDocumentMarkers();
123
124  // Sends out all feedback data. Resets the session-start timestamp to now.
125  // Restarts the timer that requests markers from the renderers.
126  void FlushFeedback();
127
128  // Sends out the |feedback_data|.
129  void SendFeedback(const std::vector<Misspelling>& feedback_data,
130                    bool is_first_feedback_batch);
131
132  // URL request context for the feedback senders.
133  scoped_refptr<net::URLRequestContextGetter> request_context_;
134
135  // The feedback API version.
136  const std::string api_version_;
137
138  // The language of text. The string is a BCP 47 language tag.
139  std::string language_;
140
141  // The country of origin. The string is the ISO 3166-1 alpha-3 code.
142  std::string country_;
143
144  // Misspelling counter used to generate unique hash identifier for each
145  // misspelling.
146  size_t misspelling_counter_;
147
148  // Feedback data.
149  Feedback feedback_;
150
151  // A set of renderer process IDs for renderers that have sent out feedback in
152  // this session.
153  std::set<int> renderers_sent_feedback_;
154
155  // When the session started.
156  base::Time session_start_;
157
158  // The URL where the feedback data should be sent.
159  GURL feedback_service_url_;
160
161  // A timer to periodically request a list of document spelling markers from
162  // all of the renderers. The timer starts in StartFeedbackCollection() and
163  // stops in StopFeedbackCollection(). The timer stops and abandons its tasks
164  // on destruction.
165  base::RepeatingTimer<FeedbackSender> timer_;
166
167  // Feedback senders that need to stay alive for the duration of sending data.
168  // If a sender is destroyed before it finishes, then sending feedback will be
169  // canceled.
170  ScopedVector<net::URLFetcher> senders_;
171
172  DISALLOW_COPY_AND_ASSIGN(FeedbackSender);
173};
174
175}  // namespace spellcheck
176
177#endif  // CHROME_BROWSER_SPELLCHECKER_FEEDBACK_SENDER_H_
178