12da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// Copyright 2013 The Chromium Authors. All rights reserved. 22da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// Use of this source code is governed by a BSD-style license that can be 32da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// found in the LICENSE file. 42da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 52da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#ifndef CHROME_BROWSER_PROFILE_RESETTER_AUTOMATIC_PROFILE_RESETTER_H_ 62da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#define CHROME_BROWSER_PROFILE_RESETTER_AUTOMATIC_PROFILE_RESETTER_H_ 72da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 82da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include <string> 92da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "base/basictypes.h" 112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "base/memory/ref_counted.h" 122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "base/memory/scoped_ptr.h" 132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "base/memory/weak_ptr.h" 142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "base/strings/string_piece.h" 152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "base/task_runner.h" 162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "chrome/browser/profile_resetter/automatic_profile_resetter_mementos.h" 172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "components/keyed_service/core/keyed_service.h" 182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 192da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass AutomaticProfileResetterDelegate; 202da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass Profile; 212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 222da489cd246702bee5938545b18a6f710ed214bcJamie Gennisnamespace base { 232da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass DictionaryValue; 242da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass ListValue; 252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis} 262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// This service is responsible for evaluating whether the criteria for showing 282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// the one-time profile reset prompt are satisfied, and for potentially 292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// triggering the prompt. To ensure that the prompt only appears at most once 302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// for any given profile, a "memento" that the prompt has appeared is written to 312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// the profile on disk; see automatic_profile_resetter_mementos.h for details. 322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// The service is created automatically with the Profile and is activated right 332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// away by its factory. To avoid delaying start-up, however, it will only start 342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// working after a short delay. 352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// All methods in this class shall be called on the UI thread, except when noted 362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// otherwise. 372da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass AutomaticProfileResetter : public KeyedService { 382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis public: 392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // Enumeration listing the possible outcomes of triggering the profile reset 402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // prompt. 412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis enum PromptResult { 422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // The reset prompt was not triggered because only a dry-run was performed, 432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // or because it was not supported on the current platform. 442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis PROMPT_NOT_TRIGGERED, 452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // The reset bubble actually got shown. In contrast to the wrench menu item 462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // that can always be shown, the bubble might be delayed or might never be 472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // shown if another bubble was shown at the time of triggering the prompt. 482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // This enumeration value is usually recorded in conjunction with another 492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // PromptResult, the absence of which indicates that the prompt was ignored. 502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis PROMPT_SHOWN_BUBBLE, 512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // The user selected "Reset" or "No, thanks" (respectively) directly from 522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // within the bubble. 532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis PROMPT_ACTION_RESET, 542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis PROMPT_ACTION_NO_RESET, 552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // The reset bubble was shown, then dismissed without taking definitive 562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // action. Then, however, the user initiated or refrained from doing a reset 572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // (respectively) from the conventional, WebUI-based reset dialog. 582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis PROMPT_FOLLOWED_BY_WEBUI_RESET, 592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis PROMPT_FOLLOWED_BY_WEBUI_NO_RESET, 602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // The reset bubble was suppressed (not shown) because another bubble was 612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // already being shown at the time. Regardless, however, the user initiated 622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // or refrained from doing a reset (respectively) from the conventional, 632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // WebUI-based reset dialog. 642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis PROMPT_NOT_SHOWN_BUBBLE_BUT_HAD_WEBUI_RESET, 652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis PROMPT_NOT_SHOWN_BUBBLE_BUT_HAD_WEBUI_NO_RESET, 662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis PROMPT_RESULT_MAX 672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis }; 682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis explicit AutomaticProfileResetter(Profile* profile); 702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis virtual ~AutomaticProfileResetter(); 712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // Initializes the service if it is enabled in the field trial. Otherwise, 732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // skips the initialization steps, and also permanently disables the service. 742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // Called by AutomaticProfileResetterFactory. 752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis void Initialize(); 762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // Fires up the service by unleashing the asynchronous evaluation flow, unless 782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // the service has been already disabled in Initialize() or there is no 792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // |program_| to run (in which case the service also gets disabled). 802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // Called by the AutomaticProfileResetterFactory. 812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis void Activate(); 822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // Called in case the user chooses to reset their profile settings from inside 842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // the reset bubble. Will trigger the reset, optionally |send_feedback|, and 852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // conclude the reset prompt flow. 862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis void TriggerProfileReset(bool send_feedback); 872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // Called in case the user chooses from inside the reset bubble that they do 892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // not want to reset their profile settings. Will conclude the reset prompt 902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // flow without setting off a reset. 912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis void SkipProfileReset(); 922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // Returns whether or not the profile reset prompt flow is currently active, 942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // that is, we have triggered the prompt and are waiting for the user to take 952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // definitive action (and we are not yet performing a reset). 962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis bool IsResetPromptFlowActive() const; 972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // Returns whether or not the profile reset banner should be shown on the 992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // WebUI-based settings page. 1002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis bool ShouldShowResetBanner() const; 1012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // Called to give notice that the reset bubble has actually been shown. 1032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis void NotifyDidShowResetBubble(); 1042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // Called to give notice that the conventional, WebUI-based settings reset 1062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis // 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 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