Home | History | Annotate | Download | only in profile_resetter
      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 
    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