sync_setup_flow.h revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2006-2008 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_SYNC_SYNC_SETUP_FLOW_H_
6#define CHROME_BROWSER_SYNC_SYNC_SETUP_FLOW_H_
7#pragma once
8
9#include <string>
10#include <vector>
11
12#include "app/l10n_util.h"
13#include "base/gtest_prod_util.h"
14#include "base/time.h"
15#include "chrome/browser/dom_ui/html_dialog_ui.h"
16#include "chrome/browser/sync/profile_sync_service.h"
17#include "chrome/browser/sync/sync_setup_wizard.h"
18#include "gfx/native_widget_types.h"
19#include "grit/generated_resources.h"
20
21class FlowHandler;
22class SyncSetupFlowContainer;
23
24// The state machine used by SyncSetupWizard, exposed in its own header
25// to facilitate testing of SyncSetupWizard.  This class is used to open and
26// run the html dialog and deletes itself when the dialog closes.
27class SyncSetupFlow : public HtmlDialogUIDelegate {
28 public:
29  virtual ~SyncSetupFlow();
30
31  // Runs a flow from |start| to |end|, and does the work of actually showing
32  // the HTML dialog.  |container| is kept up-to-date with the lifetime of the
33  // flow (e.g it is emptied on dialog close).
34  static SyncSetupFlow* Run(ProfileSyncService* service,
35                            SyncSetupFlowContainer* container,
36                            SyncSetupWizard::State start,
37                            SyncSetupWizard::State end,
38                            gfx::NativeWindow parent_window);
39
40  // Fills |args| with "user" and "error" arguments by querying |service|.
41  static void GetArgsForGaiaLogin(
42      const ProfileSyncService* service,
43      DictionaryValue* args);
44
45  // Fills |args| with "user" and "error" arguments by querying |service|.
46  static void GetArgsForChooseDataTypes(
47      ProfileSyncService* service,
48      DictionaryValue* args);
49
50  // Triggers a state machine transition to advance_state.
51  void Advance(SyncSetupWizard::State advance_state);
52
53  // Focuses the dialog.  This is useful in cases where the dialog has been
54  // obscured by a browser window.
55  void Focus();
56
57  // HtmlDialogUIDelegate implementation.
58  // Get the HTML file path for the content to load in the dialog.
59  virtual GURL GetDialogContentURL() const {
60    return GURL("chrome://syncresources/setup");
61  }
62
63  // HtmlDialogUIDelegate implementation.
64  virtual void GetDOMMessageHandlers(
65      std::vector<DOMMessageHandler*>* handlers) const;
66
67  // HtmlDialogUIDelegate implementation.
68  // Get the size of the dialog.
69  virtual void GetDialogSize(gfx::Size* size) const;
70
71  // HtmlDialogUIDelegate implementation.
72  // Gets the JSON string input to use when opening the dialog.
73  virtual std::string GetDialogArgs() const {
74    return dialog_start_args_;
75  }
76
77  // HtmlDialogUIDelegate implementation.
78  // A callback to notify the delegate that the dialog closed.
79  virtual void OnDialogClosed(const std::string& json_retval);
80
81  // HtmlDialogUIDelegate implementation.
82  virtual void OnCloseContents(TabContents* source, bool* out_close_dialog) { }
83
84  // HtmlDialogUIDelegate implementation.
85  virtual std::wstring GetDialogTitle() const {
86    return l10n_util::GetString(IDS_SYNC_MY_BOOKMARKS_LABEL);
87  }
88
89  // HtmlDialogUIDelegate implementation.
90  virtual bool IsDialogModal() const {
91    return false;
92  }
93
94  void OnUserSubmittedAuth(const std::string& username,
95                           const std::string& password,
96                           const std::string& captcha) {
97    service_->OnUserSubmittedAuth(username, password, captcha);
98  }
99
100  void OnUserChoseDataTypes(bool sync_everything,
101      syncable::ModelTypeSet& chosen_types) {
102    service_->OnUserChoseDatatypes(sync_everything, chosen_types);
103  }
104
105 private:
106  FRIEND_TEST_ALL_PREFIXES(SyncSetupWizardTest, InitialStepLogin);
107  FRIEND_TEST_ALL_PREFIXES(SyncSetupWizardTest, ChooseDataTypesSetsPrefs);
108  FRIEND_TEST_ALL_PREFIXES(SyncSetupWizardTest, DialogCancelled);
109  FRIEND_TEST_ALL_PREFIXES(SyncSetupWizardTest, InvalidTransitions);
110  FRIEND_TEST_ALL_PREFIXES(SyncSetupWizardTest, FullSuccessfulRunSetsPref);
111  FRIEND_TEST_ALL_PREFIXES(SyncSetupWizardTest, AbortedByPendingClear);
112  FRIEND_TEST_ALL_PREFIXES(SyncSetupWizardTest, DiscreteRunGaiaLogin);
113  FRIEND_TEST_ALL_PREFIXES(SyncSetupWizardTest, DiscreteRunChooseDataTypes);
114  FRIEND_TEST_ALL_PREFIXES(SyncSetupWizardTest,
115                           DiscreteRunChooseDataTypesAbortedByPendingClear);
116
117  // Use static Run method to get an instance.
118  SyncSetupFlow(SyncSetupWizard::State start_state,
119                SyncSetupWizard::State end_state,
120                const std::string& args, SyncSetupFlowContainer* container,
121                ProfileSyncService* service);
122
123  // Returns true if |this| should transition its state machine to |state|
124  // based on |current_state_|, or false if that would be nonsense or is
125  // a no-op.
126  bool ShouldAdvance(SyncSetupWizard::State state);
127
128  SyncSetupFlowContainer* container_;  // Our container.  Don't own this.
129  std::string dialog_start_args_;  // The args to pass to the initial page.
130
131  SyncSetupWizard::State current_state_;
132  SyncSetupWizard::State end_state_;  // The goal.
133
134  // Time that the GAIA_LOGIN step was received.
135  base::TimeTicks login_start_time_;
136
137  // The handler needed for the entire flow.
138  FlowHandler* flow_handler_;
139  mutable bool owns_flow_handler_;
140
141  // We need this to write the sentinel "setup completed" pref.
142  ProfileSyncService* service_;
143
144  // Currently used only on OS X
145  // TODO(akalin): Add the necessary support to the other OSes and use
146  // this for them.
147  gfx::NativeWindow html_dialog_window_;
148
149  DISALLOW_COPY_AND_ASSIGN(SyncSetupFlow);
150};
151
152// A really simple wrapper for a SyncSetupFlow so that we don't have to
153// add any public methods to the public SyncSetupWizard interface to notify it
154// when the dialog closes.
155class SyncSetupFlowContainer {
156 public:
157  SyncSetupFlowContainer() : flow_(NULL) { }
158  void set_flow(SyncSetupFlow* flow) {
159    DCHECK(!flow_ || !flow);
160    flow_ = flow;
161  }
162
163  SyncSetupFlow* get_flow() { return flow_; }
164 private:
165  SyncSetupFlow* flow_;
166
167  DISALLOW_COPY_AND_ASSIGN(SyncSetupFlowContainer);
168};
169
170// The FlowHandler connects the state machine to the dialog backing HTML and
171// JS namespace by implementing DOMMessageHandler and being invoked by the
172// SyncSetupFlow.  Exposed here to facilitate testing.
173class FlowHandler : public DOMMessageHandler {
174 public:
175  FlowHandler()  {}
176  virtual ~FlowHandler() {}
177
178  // DOMMessageHandler implementation.
179  virtual void RegisterMessages();
180
181  // Callbacks from the page.
182  void HandleSubmitAuth(const ListValue* args);
183  void HandleChooseDataTypes(const ListValue* args);
184
185  // These functions control which part of the HTML is visible.
186  void ShowGaiaLogin(const DictionaryValue& args);
187  void ShowGaiaSuccessAndClose();
188  void ShowGaiaSuccessAndSettingUp();
189  void ShowChooseDataTypes(const DictionaryValue& args);
190  void ShowSetupDone(const std::wstring& user);
191  void ShowFirstTimeDone(const std::wstring& user);
192
193  void set_flow(SyncSetupFlow* flow) {
194    flow_ = flow;
195  }
196
197 private:
198  void ExecuteJavascriptInIFrame(const std::wstring& iframe_xpath,
199                                 const std::wstring& js);
200  SyncSetupFlow* flow_;
201  DISALLOW_COPY_AND_ASSIGN(FlowHandler);
202};
203
204#endif  // CHROME_BROWSER_SYNC_SYNC_SETUP_FLOW_H_
205