| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_PROFILE_RESETTER_AUTOMATIC_PROFILE_RESETTER_H_ |
| #define CHROME_BROWSER_PROFILE_RESETTER_AUTOMATIC_PROFILE_RESETTER_H_ |
| |
| #include <string> |
| |
| #include "base/basictypes.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/strings/string_piece.h" |
| #include "base/task_runner.h" |
| #include "chrome/browser/profile_resetter/automatic_profile_resetter_mementos.h" |
| #include "components/keyed_service/core/keyed_service.h" |
| |
| class AutomaticProfileResetterDelegate; |
| class Profile; |
| |
| namespace base { |
| class DictionaryValue; |
| class ListValue; |
| } |
| |
| // This service is responsible for evaluating whether the criteria for showing |
| // the one-time profile reset prompt are satisfied, and for potentially |
| // triggering the prompt. To ensure that the prompt only appears at most once |
| // for any given profile, a "memento" that the prompt has appeared is written to |
| // the profile on disk; see automatic_profile_resetter_mementos.h for details. |
| // The service is created automatically with the Profile and is activated right |
| // away by its factory. To avoid delaying start-up, however, it will only start |
| // working after a short delay. |
| // All methods in this class shall be called on the UI thread, except when noted |
| // otherwise. |
| class AutomaticProfileResetter : public KeyedService { |
| public: |
| // Enumeration listing the possible outcomes of triggering the profile reset |
| // prompt. |
| enum PromptResult { |
| // The reset prompt was not triggered because only a dry-run was performed, |
| // or because it was not supported on the current platform. |
| PROMPT_NOT_TRIGGERED, |
| // The reset bubble actually got shown. In contrast to the wrench menu item |
| // that can always be shown, the bubble might be delayed or might never be |
| // shown if another bubble was shown at the time of triggering the prompt. |
| // This enumeration value is usually recorded in conjunction with another |
| // PromptResult, the absence of which indicates that the prompt was ignored. |
| PROMPT_SHOWN_BUBBLE, |
| // The user selected "Reset" or "No, thanks" (respectively) directly from |
| // within the bubble. |
| PROMPT_ACTION_RESET, |
| PROMPT_ACTION_NO_RESET, |
| // The reset bubble was shown, then dismissed without taking definitive |
| // action. Then, however, the user initiated or refrained from doing a reset |
| // (respectively) from the conventional, WebUI-based reset dialog. |
| PROMPT_FOLLOWED_BY_WEBUI_RESET, |
| PROMPT_FOLLOWED_BY_WEBUI_NO_RESET, |
| // The reset bubble was suppressed (not shown) because another bubble was |
| // already being shown at the time. Regardless, however, the user initiated |
| // or refrained from doing a reset (respectively) from the conventional, |
| // WebUI-based reset dialog. |
| PROMPT_NOT_SHOWN_BUBBLE_BUT_HAD_WEBUI_RESET, |
| PROMPT_NOT_SHOWN_BUBBLE_BUT_HAD_WEBUI_NO_RESET, |
| PROMPT_RESULT_MAX |
| }; |
| |
| explicit AutomaticProfileResetter(Profile* profile); |
| virtual ~AutomaticProfileResetter(); |
| |
| // Initializes the service if it is enabled in the field trial. Otherwise, |
| // skips the initialization steps, and also permanently disables the service. |
| // Called by AutomaticProfileResetterFactory. |
| void Initialize(); |
| |
| // Fires up the service by unleashing the asynchronous evaluation flow, unless |
| // the service has been already disabled in Initialize() or there is no |
| // |program_| to run (in which case the service also gets disabled). |
| // Called by the AutomaticProfileResetterFactory. |
| void Activate(); |
| |
| // Called in case the user chooses to reset their profile settings from inside |
| // the reset bubble. Will trigger the reset, optionally |send_feedback|, and |
| // conclude the reset prompt flow. |
| void TriggerProfileReset(bool send_feedback); |
| |
| // Called in case the user chooses from inside the reset bubble that they do |
| // not want to reset their profile settings. Will conclude the reset prompt |
| // flow without setting off a reset. |
| void SkipProfileReset(); |
| |
| // Returns whether or not the profile reset prompt flow is currently active, |
| // that is, we have triggered the prompt and are waiting for the user to take |
| // definitive action (and we are not yet performing a reset). |
| bool IsResetPromptFlowActive() const; |
| |
| // Returns whether or not the profile reset banner should be shown on the |
| // WebUI-based settings page. |
| bool ShouldShowResetBanner() const; |
| |
| // Called to give notice that the reset bubble has actually been shown. |
| void NotifyDidShowResetBubble(); |
| |
| // Called to give notice that the conventional, WebUI-based settings reset |
| // dialog has been opened. This will dismiss the menu item in the wrench menu. |
| // This should always be followed by a corresponding call to |
| // NotifyDidCloseWebUIResetDialog(). |
| void NotifyDidOpenWebUIResetDialog(); |
| |
| // Called to give notice that the conventional, WebUI-based settings reset |
| // dialog has been closed, with |performed_reset| indicating whether or not a |
| // reset was requested. This is required so that we can record the appropriate |
| // PromptResult, dismiss the prompt, and conclude the reset prompt flow early |
| // without setting off any resets in the future. |
| void NotifyDidCloseWebUIResetDialog(bool performed_reset); |
| |
| // Called to give notice that reset banner has been dismissed as a result of |
| // user action on the WebUI-based settings page itself. |
| void NotifyDidCloseWebUIResetBanner(); |
| |
| base::WeakPtr<AutomaticProfileResetter> AsWeakPtr() { |
| return weak_ptr_factory_.GetWeakPtr(); |
| } |
| |
| // Should be called before Activate(). |
| void SetProgramForTesting(const std::string& program); |
| |
| // Should be called before Activate(). |
| void SetHashSeedForTesting(const std::string& hash_seed); |
| |
| // Should be called before Activate(). |
| void SetDelegateForTesting( |
| scoped_ptr<AutomaticProfileResetterDelegate> delegate); |
| |
| // Should be called before Activate(). Sets the task runner to be used to post |
| // task |PrepareEvaluationFlow| in a delayed manner. |
| void SetTaskRunnerForWaitingForTesting( |
| const scoped_refptr<base::TaskRunner>& task_runner); |
| |
| // KeyedService: |
| virtual void Shutdown() OVERRIDE; |
| |
| private: |
| class InputBuilder; |
| struct EvaluationResults; |
| |
| enum State { |
| STATE_UNINITIALIZED, |
| STATE_INITIALIZED, |
| STATE_DISABLED, |
| STATE_WAITING_ON_DEPENDENCIES, |
| STATE_READY, |
| STATE_EVALUATING_CONDITIONS, |
| // The reset prompt has been triggered; but the reset bubble has not yet |
| // been shown. |
| STATE_HAS_TRIGGERED_PROMPT, |
| // The reset prompt has been triggered; the reset bubble has been shown, and |
| // potentially already dismissed by the user. |
| STATE_HAS_SHOWN_BUBBLE, |
| STATE_PERFORMING_RESET, |
| STATE_DONE |
| }; |
| |
| // Prepares the asynchronous evaluation flow by requesting services that it |
| // depends on to make themselves ready. |
| void PrepareEvaluationFlow(); |
| |
| // Called back by |resetter_delegate_| when the template URL service is ready. |
| void OnTemplateURLServiceIsLoaded(); |
| |
| // Called back by |resetter_delegate_| when the loaded modules have been |
| // enumerated. |
| void OnLoadedModulesAreEnumerated(); |
| |
| // Invoked by the above two methods. Kicks off the actual evaluation flow. |
| void OnDependencyIsReady(); |
| |
| // Begins the asynchronous evaluation flow, which will assess whether the |
| // criteria for showing the reset prompt are met, whether we have already |
| // shown the prompt; and, in the end, will potentially trigger the prompt. |
| void BeginEvaluationFlow(); |
| |
| // Called by InputBuilder once it has finished assembling the |program_input|, |
| // and will continue with the evaluation flow by triggering the evaluator |
| // program on the worker thread. |
| void ContinueWithEvaluationFlow( |
| scoped_ptr<base::DictionaryValue> program_input); |
| |
| // Performs the bulk of the work. Invokes the JTL interpreter to run the |
| // |program| that will evaluate whether the conditions are met for showing the |
| // reset prompt. The program will make this decision based on the state |
| // information contained in |input| in the form of key-value pairs. The |
| // program will only see hashed keys and values that are produced using |
| // |hash_seed| as a key. |
| static scoped_ptr<EvaluationResults> EvaluateConditionsOnWorkerPoolThread( |
| const std::string& hash_seed, |
| const std::string& program, |
| scoped_ptr<base::DictionaryValue> program_input); |
| |
| // Reports the given metrics through UMA. Virtual, so it can be mocked out in |
| // tests to verify that the correct value are being reported. |
| virtual void ReportStatistics(uint32 satisfied_criteria_mask, |
| uint32 combined_status_mask); |
| |
| // Called back when EvaluateConditionsOnWorkerPoolThread completes executing |
| // the program with |results|. Finishes the evaluation flow, and, based on the |
| // result, potentially initiates the reset prompt flow. |
| void FinishEvaluationFlow(scoped_ptr<EvaluationResults> results); |
| |
| // Begins the reset prompt flow by triggering the reset prompt, which consists |
| // of two parts: (1.) the profile reset (pop-up) bubble, and (2.) a menu item |
| // in the wrench menu (provided by a GlobalError). |
| // The flow lasts until we receive a clear indication from the user about |
| // whether or not they wish to reset their settings. This indication can come |
| // in a variety of flavors: |
| // * taking definitive action (i.e. selecting either "Reset" or "No, thanks") |
| // in the pop-up reset bubble itself, |
| // * dismissing the bubble, but then selecting the wrench menu item, which |
| // takes them to the WebUI reset dialog in chrome://settings, and then the |
| // user can make their choice there, |
| // * the user going to the WebUI reset dialog by themself. |
| // For the most part, the conclusion of the reset flow coincides with when the |
| // reset prompt is dismissed, with the one exception being that the prompt is |
| // closed as soon as the WebUI reset dialog is opened, we do not wait until |
| // the user actually makes a choice in that dialog. |
| void BeginResetPromptFlow(); |
| |
| // Called back by the ProfileResetter once resetting the profile settings has |
| // been completed, when requested by the user from inside the reset bubble. |
| // Will dismiss the prompt and conclude the reset prompt flow. |
| void OnProfileSettingsResetCompleted(); |
| |
| // Reports the result of triggering the prompt through UMA. Virtual, so it can |
| // be mocked out in tests to verify that the correct value is being reported. |
| virtual void ReportPromptResult(PromptResult result); |
| |
| // Writes the memento values returned by the evaluation program to disk, and |
| // then destroys |evaluation_results_|. |
| void PersistMementos(); |
| |
| // Concludes the reset prompt flow. |
| void FinishResetPromptFlow(); |
| |
| Profile* profile_; |
| |
| State state_; |
| bool enumeration_of_loaded_modules_ready_; |
| bool template_url_service_ready_; |
| bool has_already_dismissed_prompt_; |
| |
| scoped_ptr<InputBuilder> input_builder_; |
| std::string hash_seed_; |
| std::string program_; |
| |
| scoped_ptr<EvaluationResults> evaluation_results_; |
| |
| bool should_show_reset_banner_; |
| |
| scoped_ptr<AutomaticProfileResetterDelegate> delegate_; |
| scoped_refptr<base::TaskRunner> task_runner_for_waiting_; |
| |
| base::WeakPtrFactory<AutomaticProfileResetter> weak_ptr_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AutomaticProfileResetter); |
| }; |
| |
| #endif // CHROME_BROWSER_PROFILE_RESETTER_AUTOMATIC_PROFILE_RESETTER_H_ |