• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #ifndef CHROME_BROWSER_PROFILE_RESETTER_AUTOMATIC_PROFILE_RESETTER_H_
6 #define CHROME_BROWSER_PROFILE_RESETTER_AUTOMATIC_PROFILE_RESETTER_H_
7 
8 #include <string>
9 
10 #include "base/basictypes.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/strings/string_piece.h"
15 #include "base/task_runner.h"
16 #include "chrome/browser/profile_resetter/automatic_profile_resetter_mementos.h"
17 #include "components/keyed_service/core/keyed_service.h"
18 
19 class AutomaticProfileResetterDelegate;
20 class Profile;
21 
22 namespace base {
23 class DictionaryValue;
24 class ListValue;
25 }
26 
27 // This service is responsible for evaluating whether the criteria for showing
28 // the one-time profile reset prompt are satisfied, and for potentially
29 // triggering the prompt. To ensure that the prompt only appears at most once
30 // for any given profile, a "memento" that the prompt has appeared is written to
31 // the profile on disk; see automatic_profile_resetter_mementos.h for details.
32 // The service is created automatically with the Profile and is activated right
33 // away by its factory. To avoid delaying start-up, however, it will only start
34 // working after a short delay.
35 // All methods in this class shall be called on the UI thread, except when noted
36 // otherwise.
37 class AutomaticProfileResetter : public KeyedService {
38  public:
39   // Enumeration listing the possible outcomes of triggering the profile reset
40   // prompt.
41   enum PromptResult {
42     // The reset prompt was not triggered because only a dry-run was performed,
43     // or because it was not supported on the current platform.
44     PROMPT_NOT_TRIGGERED,
45     // The reset bubble actually got shown. In contrast to the wrench menu item
46     // that can always be shown, the bubble might be delayed or might never be
47     // shown if another bubble was shown at the time of triggering the prompt.
48     // This enumeration value is usually recorded in conjunction with another
49     // PromptResult, the absence of which indicates that the prompt was ignored.
50     PROMPT_SHOWN_BUBBLE,
51     // The user selected "Reset" or "No, thanks" (respectively) directly from
52     // within the bubble.
53     PROMPT_ACTION_RESET,
54     PROMPT_ACTION_NO_RESET,
55     // The reset bubble was shown, then dismissed without taking definitive
56     // action. Then, however, the user initiated or refrained from doing a reset
57     // (respectively) from the conventional, WebUI-based reset dialog.
58     PROMPT_FOLLOWED_BY_WEBUI_RESET,
59     PROMPT_FOLLOWED_BY_WEBUI_NO_RESET,
60     // The reset bubble was suppressed (not shown) because another bubble was
61     // already being shown at the time. Regardless, however, the user initiated
62     // or refrained from doing a reset (respectively) from the conventional,
63     // WebUI-based reset dialog.
64     PROMPT_NOT_SHOWN_BUBBLE_BUT_HAD_WEBUI_RESET,
65     PROMPT_NOT_SHOWN_BUBBLE_BUT_HAD_WEBUI_NO_RESET,
66     PROMPT_RESULT_MAX
67   };
68 
69   explicit AutomaticProfileResetter(Profile* profile);
70   virtual ~AutomaticProfileResetter();
71 
72   // Initializes the service if it is enabled in the field trial. Otherwise,
73   // skips the initialization steps, and also permanently disables the service.
74   // Called by AutomaticProfileResetterFactory.
75   void Initialize();
76 
77   // Fires up the service by unleashing the asynchronous evaluation flow, unless
78   // the service has been already disabled in Initialize() or there is no
79   // |program_| to run (in which case the service also gets disabled).
80   // Called by the AutomaticProfileResetterFactory.
81   void Activate();
82 
83   // Called in case the user chooses to reset their profile settings from inside
84   // the reset bubble. Will trigger the reset, optionally |send_feedback|, and
85   // conclude the reset prompt flow.
86   void TriggerProfileReset(bool send_feedback);
87 
88   // Called in case the user chooses from inside the reset bubble that they do
89   // not want to reset their profile settings. Will conclude the reset prompt
90   // flow without setting off a reset.
91   void SkipProfileReset();
92 
93   // Returns whether or not the profile reset prompt flow is currently active,
94   // that is, we have triggered the prompt and are waiting for the user to take
95   // definitive action (and we are not yet performing a reset).
96   bool IsResetPromptFlowActive() const;
97 
98   // Returns whether or not the profile reset banner should be shown on the
99   // WebUI-based settings page.
100   bool ShouldShowResetBanner() const;
101 
102   // Called to give notice that the reset bubble has actually been shown.
103   void NotifyDidShowResetBubble();
104 
105   // Called to give notice that the conventional, WebUI-based settings reset
106   // dialog has been opened. This will dismiss the menu item in the wrench menu.
107   // This should always be followed by a corresponding call to
108   // NotifyDidCloseWebUIResetDialog().
109   void NotifyDidOpenWebUIResetDialog();
110 
111   // Called to give notice that the conventional, WebUI-based settings reset
112   // dialog has been closed, with |performed_reset| indicating whether or not a
113   // reset was requested. This is required so that we can record the appropriate
114   // PromptResult, dismiss the prompt, and conclude the reset prompt flow early
115   // without setting off any resets in the future.
116   void NotifyDidCloseWebUIResetDialog(bool performed_reset);
117 
118   // Called to give notice that reset banner has been dismissed as a result of
119   // user action on the WebUI-based settings page itself.
120   void NotifyDidCloseWebUIResetBanner();
121 
AsWeakPtr()122   base::WeakPtr<AutomaticProfileResetter> AsWeakPtr() {
123     return weak_ptr_factory_.GetWeakPtr();
124   }
125 
126   // Should be called before Activate().
127   void SetProgramForTesting(const std::string& program);
128 
129   // Should be called before Activate().
130   void SetHashSeedForTesting(const std::string& hash_seed);
131 
132   // Should be called before Activate().
133   void SetDelegateForTesting(
134       scoped_ptr<AutomaticProfileResetterDelegate> delegate);
135 
136   // Should be called before Activate(). Sets the task runner to be used to post
137   // task |PrepareEvaluationFlow| in a delayed manner.
138   void SetTaskRunnerForWaitingForTesting(
139       const scoped_refptr<base::TaskRunner>& task_runner);
140 
141   // KeyedService:
142   virtual void Shutdown() OVERRIDE;
143 
144  private:
145   class InputBuilder;
146   struct EvaluationResults;
147 
148   enum State {
149     STATE_UNINITIALIZED,
150     STATE_INITIALIZED,
151     STATE_DISABLED,
152     STATE_WAITING_ON_DEPENDENCIES,
153     STATE_READY,
154     STATE_EVALUATING_CONDITIONS,
155     // The reset prompt has been triggered; but the reset bubble has not yet
156     // been shown.
157     STATE_HAS_TRIGGERED_PROMPT,
158     // The reset prompt has been triggered; the reset bubble has been shown, and
159     // potentially already dismissed by the user.
160     STATE_HAS_SHOWN_BUBBLE,
161     STATE_PERFORMING_RESET,
162     STATE_DONE
163   };
164 
165   // Prepares the asynchronous evaluation flow by requesting services that it
166   // depends on to make themselves ready.
167   void PrepareEvaluationFlow();
168 
169   // Called back by |resetter_delegate_| when the template URL service is ready.
170   void OnTemplateURLServiceIsLoaded();
171 
172   // Called back by |resetter_delegate_| when the loaded modules have been
173   // enumerated.
174   void OnLoadedModulesAreEnumerated();
175 
176   // Invoked by the above two methods. Kicks off the actual evaluation flow.
177   void OnDependencyIsReady();
178 
179   // Begins the asynchronous evaluation flow, which will assess whether the
180   // criteria for showing the reset prompt are met, whether we have already
181   // shown the prompt; and, in the end, will potentially trigger the prompt.
182   void BeginEvaluationFlow();
183 
184   // Called by InputBuilder once it has finished assembling the |program_input|,
185   // and will continue with the evaluation flow by triggering the evaluator
186   // program on the worker thread.
187   void ContinueWithEvaluationFlow(
188       scoped_ptr<base::DictionaryValue> program_input);
189 
190   // Performs the bulk of the work. Invokes the JTL interpreter to run the
191   // |program| that will evaluate whether the conditions are met for showing the
192   // reset prompt. The program will make this decision based on the state
193   // information contained in |input| in the form of key-value pairs. The
194   // program will only see hashed keys and values that are produced using
195   // |hash_seed| as a key.
196   static scoped_ptr<EvaluationResults> EvaluateConditionsOnWorkerPoolThread(
197       const std::string& hash_seed,
198       const std::string& program,
199       scoped_ptr<base::DictionaryValue> program_input);
200 
201   // Reports the given metrics through UMA. Virtual, so it can be mocked out in
202   // tests to verify that the correct value are being reported.
203   virtual void ReportStatistics(uint32 satisfied_criteria_mask,
204                                 uint32 combined_status_mask);
205 
206   // Called back when EvaluateConditionsOnWorkerPoolThread completes executing
207   // the program with |results|. Finishes the evaluation flow, and, based on the
208   // result, potentially initiates the reset prompt flow.
209   void FinishEvaluationFlow(scoped_ptr<EvaluationResults> results);
210 
211   // Begins the reset prompt flow by triggering the reset prompt, which consists
212   // of two parts: (1.) the profile reset (pop-up) bubble, and (2.) a menu item
213   // in the wrench menu (provided by a GlobalError).
214   // The flow lasts until we receive a clear indication from the user about
215   // whether or not they wish to reset their settings. This indication can come
216   // in a variety of flavors:
217   //  * taking definitive action (i.e. selecting either "Reset" or "No, thanks")
218   //    in the pop-up reset bubble itself,
219   //  * dismissing the bubble, but then selecting the wrench menu item, which
220   //    takes them to the WebUI reset dialog in chrome://settings, and then the
221   //    user can make their choice there,
222   //  * the user going to the WebUI reset dialog by themself.
223   // For the most part, the conclusion of the reset flow coincides with when the
224   // reset prompt is dismissed, with the one exception being that the prompt is
225   // closed as soon as the WebUI reset dialog is opened, we do not wait until
226   // the user actually makes a choice in that dialog.
227   void BeginResetPromptFlow();
228 
229   // Called back by the ProfileResetter once resetting the profile settings has
230   // been completed, when requested by the user from inside the reset bubble.
231   // Will dismiss the prompt and conclude the reset prompt flow.
232   void OnProfileSettingsResetCompleted();
233 
234   // Reports the result of triggering the prompt through UMA. Virtual, so it can
235   // be mocked out in tests to verify that the correct value is being reported.
236   virtual void ReportPromptResult(PromptResult result);
237 
238   // Writes the memento values returned by the evaluation program to disk, and
239   // then destroys |evaluation_results_|.
240   void PersistMementos();
241 
242   // Concludes the reset prompt flow.
243   void FinishResetPromptFlow();
244 
245   Profile* profile_;
246 
247   State state_;
248   bool enumeration_of_loaded_modules_ready_;
249   bool template_url_service_ready_;
250   bool has_already_dismissed_prompt_;
251 
252   scoped_ptr<InputBuilder> input_builder_;
253   std::string hash_seed_;
254   std::string program_;
255 
256   scoped_ptr<EvaluationResults> evaluation_results_;
257 
258   bool should_show_reset_banner_;
259 
260   scoped_ptr<AutomaticProfileResetterDelegate> delegate_;
261   scoped_refptr<base::TaskRunner> task_runner_for_waiting_;
262 
263   base::WeakPtrFactory<AutomaticProfileResetter> weak_ptr_factory_;
264 
265   DISALLOW_COPY_AND_ASSIGN(AutomaticProfileResetter);
266 };
267 
268 #endif  // CHROME_BROWSER_PROFILE_RESETTER_AUTOMATIC_PROFILE_RESETTER_H_
269