blob: 0301647d6b459b63da7ac718e60d73bef339f171 [file] [log] [blame]
[email protected]132c85652009-08-05 01:18:271// 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#ifdef CHROME_PERSONALIZATION
6
7#ifndef CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_H_
8#define CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_H_
9
10#include <string>
11#include <map>
12#include <vector>
13
14#include "base/basictypes.h"
15#include "base/file_path.h"
16#include "base/observer_list.h"
17#include "base/scoped_ptr.h"
18#include "chrome/browser/bookmarks/bookmark_model.h"
19#include "chrome/browser/profile.h"
20#include "chrome/browser/sync/glue/model_associator.h"
21#include "chrome/browser/sync/glue/sync_backend_host.h"
22#include "chrome/browser/views/sync/sync_setup_wizard.h"
23#include "googleurl/src/gurl.h"
24
25class CommandLine;
26class MessageLoop;
27class Profile;
28
29namespace browser_sync {
30class ModelAssociator;
31}
32
33// Various UI components such as the New Tab page can be driven by observing
34// the ProfileSyncService through this interface.
35class ProfileSyncServiceObserver {
36 public:
37 // When one of the following events occurs, OnStateChanged() is called.
38 // Observers should query the service to determine what happened.
39 // - We initialized successfully.
40 // - There was an authentication error and the user needs to reauthenticate.
41 // - The sync servers are unavailable at this time.
42 // - Credentials are now in flight for authentication.
43 virtual void OnStateChanged() = 0;
44 protected:
45 virtual ~ProfileSyncServiceObserver() { }
46};
47
48// ProfileSyncService is the layer between browser subsystems like bookmarks,
49// and the sync backend.
50class ProfileSyncService : public BookmarkModelObserver,
51 public browser_sync::SyncFrontend {
52 public:
53 typedef ProfileSyncServiceObserver Observer;
54 typedef browser_sync::SyncBackendHost::Status Status;
55
[email protected]1f97a112009-08-11 02:17:0656 enum SyncEventCodes {
57 MIN_SYNC_EVENT_CODE = 0,
58
59 // Events starting the sync service.
60 START_FROM_NTP = 1, // Sync was started from the ad in NTP
61 START_FROM_WRENCH = 2, // Sync was started from the Wrench menu.
62 START_FROM_OPTIONS = 3, // Sync was started from Wrench->Options.
63
64 // Events regarding cancelation of the signon process of sync.
65 CANCEL_FROM_SIGNON_WIHTOUT_AUTH = 10, // Cancelled before submitting
66 // username and password.
67 CANCEL_DURING_SIGNON = 11, // Cancelled after auth.
68 CANCEL_DURING_SIGNON_AFTER_MERGE = 12, // Cancelled during merge.
69
70 // Events resulting in the stoppage of sync service.
71 STOP_FROM_OPTIONS = 20, // Sync was stopped from Wrench->Options.
72
73 // Miscellaneous events caused by sync service.
74 MERGE_AND_SYNC_NEEDED = 30,
75
76 MAX_SYNC_EVENT_CODE
77 };
78
[email protected]132c85652009-08-05 01:18:2779 explicit ProfileSyncService(Profile* profile);
80 virtual ~ProfileSyncService();
81
82 // Initializes the object. This should be called every time an object of this
83 // class is constructed.
84 void Initialize();
85
86 // Enables/disables sync for user.
87 virtual void EnableForUser();
88 virtual void DisableForUser();
89
90 // Whether sync is enabled by user or not.
91 bool IsSyncEnabledByUser() const;
92
93 // BookmarkModelObserver implementation.
94 virtual void Loaded(BookmarkModel* model);
95 virtual void BookmarkModelBeingDeleted(BookmarkModel* model) {}
96 virtual void BookmarkNodeMoved(BookmarkModel* model,
97 const BookmarkNode* old_parent,
98 int old_index,
99 const BookmarkNode* new_parent,
100 int new_index);
101 virtual void BookmarkNodeAdded(BookmarkModel* model,
102 const BookmarkNode* parent,
103 int index);
104 virtual void BookmarkNodeRemoved(BookmarkModel* model,
105 const BookmarkNode* parent,
106 int index,
107 const BookmarkNode* node);
108 virtual void BookmarkNodeChanged(BookmarkModel* model,
109 const BookmarkNode* node);
110 virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model,
111 const BookmarkNode* node);
112 virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
113 const BookmarkNode* node);
114
115 // SyncFrontend implementation.
116 virtual void OnBackendInitialized();
117 virtual void OnSyncCycleCompleted();
118 virtual void OnAuthError();
119 virtual void ApplyModelChanges(
120 const sync_api::BaseTransaction* trans,
121 const sync_api::SyncManager::ChangeRecord* changes,
122 int change_count);
123
124 // Called when a user enters credentials through UI.
125 virtual void OnUserSubmittedAuth(const std::string& username,
126 const std::string& password);
127
128 // Called when a user decides whether to merge and sync or abort.
129 virtual void OnUserAcceptedMergeAndSync();
130
131 // Called when a user cancels any setup dialog (login, merge and sync, etc).
132 virtual void OnUserCancelledDialog();
133
134 // Get various information for displaying in the user interface.
135 browser_sync::SyncBackendHost::StatusSummary QuerySyncStatusSummary();
136 browser_sync::SyncBackendHost::Status QueryDetailedSyncStatus();
137
138 AuthErrorState GetAuthErrorState() const {
139 return last_auth_error_;
140 }
141
142 // Displays a dialog for the user to enter GAIA credentials and attempt
143 // re-authentication, and returns true if it actually opened the dialog.
144 // Returns false if a dialog is already showing, an auth attempt is in
145 // progress, the sync system is already authenticated, or some error
146 // occurred preventing the action. We make it the duty of ProfileSyncService
147 // to open the dialog to easily ensure only one is ever showing.
148 bool SetupInProgress() const {
149 return !IsSyncEnabledByUser() && WizardIsVisible();
150 }
151 bool WizardIsVisible() const { return wizard_.IsVisible(); }
152 void ShowLoginDialog();
153
154 // Pretty-printed strings for a given StatusSummary.
155 static std::wstring BuildSyncStatusSummaryText(
156 const browser_sync::SyncBackendHost::StatusSummary& summary);
157
158 // Returns true if the SyncBackendHost has told us it's ready to accept
159 // changes.
160 // TODO(timsteele): What happens if the bookmark model is loaded, a change
161 // takes place, and the backend isn't initialized yet?
162 bool sync_initialized() const { return backend_initialized_; }
163
164 bool UIShouldDepictAuthInProgress() const {
165 return is_auth_in_progress_;
166 }
167
168 // A timestamp marking the last time the service observed a transition from
169 // the SYNCING state to the READY state. Note that this does not reflect the
170 // last time we polled the server to see if there were any changes; the
171 // timestamp is only snapped when syncing takes place and we download or
172 // upload some bookmark entity.
173 const base::Time& last_synced_time() const { return last_synced_time_; }
174
175 // Returns a user-friendly string form of last synced time (in minutes).
176 std::wstring GetLastSyncedTimeString() const;
177
178 // Returns the authenticated username of the sync user, or empty if none
179 // exists. It will only exist if the authentication service provider (e.g
180 // GAIA) has confirmed the username is authentic.
181 virtual string16 GetAuthenticatedUsername() const;
182
183 const std::string& last_attempted_user_email() const {
184 return last_attempted_user_email_;
185 }
186
187 // The profile we are syncing for.
188 Profile* profile() { return profile_; }
189
190 // Adds/removes an observer. ProfileSyncService does not take ownership of
191 // the observer.
192 void AddObserver(Observer* observer);
193 void RemoveObserver(Observer* observer);
194
[email protected]1f97a112009-08-11 02:17:06195 // Record stats on various events.
196 static void SyncEvent(SyncEventCodes code);
197
[email protected]132c85652009-08-05 01:18:27198 protected:
199 // Call this after any of the subsystems being synced (the bookmark
200 // model and the sync backend) finishes its initialization. When everything
201 // is ready, this function will bootstrap the subsystems so that they are
202 // initially in sync, and start forwarding changes between the two models.
203 void StartProcessingChangesIfReady();
204
205 // Various member accessors needed by unit tests.
206 browser_sync::SyncBackendHost* backend() { return backend_.get(); }
207
208 // Call this when normal operation detects that the bookmark model and the
209 // syncer model are inconsistent, or similar. The ProfileSyncService will
210 // try to avoid doing any work to avoid crashing or corrupting things
211 // further, and will report an error status if queried.
212 void SetUnrecoverableError();
213
214 // Returns whether processing changes is allowed. Check this before doing
215 // any model-modifying operations.
216 bool ShouldPushChanges();
217
218 // Starts up the backend sync components.
219 void StartUp();
220 // Shuts down the backend sync components.
221 // |sync_disabled| indicates if syncing is being disabled or not.
222 void Shutdown(bool sync_disabled);
223
224 // Tests need to override this.
225 virtual void InitializeBackend();
226
227 // Tests need this.
228 void set_model_associator(browser_sync::ModelAssociator* manager) {
229 model_associator_ = manager;
230 }
231
232 // We keep track of the last auth error observed so we can cover up the first
233 // "expected" auth failure from observers.
234 // TODO(timsteele): Same as expecting_first_run_auth_needed_event_. Remove
235 // this!
236 AuthErrorState last_auth_error_;
237
238 // Cache of the last name the client attempted to authenticate.
239 std::string last_attempted_user_email_;
240
241 private:
242 friend class browser_sync::ModelAssociator;
243 friend class ProfileSyncServiceTest;
244 friend class ProfileSyncServiceTestHarness;
245 friend class TestModelAssociator;
246 FRIEND_TEST(ProfileSyncServiceTest, UnrecoverableErrorSuspendsService);
247
248 enum MoveOrCreate {
249 MOVE,
250 CREATE,
251 };
252
253 // Initializes the various settings from the command line.
254 void InitSettings();
255
256 // Methods to register, load and remove preferences.
257 void RegisterPreferences();
258 void LoadPreferences();
259 void ClearPreferences();
260
261 // Treat the |index|th child of |parent| as a newly added node, and create a
262 // corresponding node in the sync domain using |trans|. All properties
263 // will be transferred to the new node. A node corresponding to |parent|
264 // must already exist and be associated for this call to succeed. Returns
265 // the ID of the just-created node, or if creation fails, kInvalidID.
266 int64 CreateSyncNode(const BookmarkNode* parent,
267 int index,
268 sync_api::WriteTransaction* trans);
269
270 // Create a bookmark node corresponding to |src| if one is not already
271 // associated with |src|. Returns the node that was created or updated.
272 const BookmarkNode* CreateOrUpdateBookmarkNode(
273 sync_api::BaseNode* src,
274 BookmarkModel* model);
275
276 // Creates a bookmark node under the given parent node from the given sync
277 // node. Returns the newly created node.
278 const BookmarkNode* CreateBookmarkNode(
279 sync_api::BaseNode* sync_node,
280 const BookmarkNode* parent,
281 int index) const;
282
283 // Sets the favicon of the given bookmark node from the given sync node.
284 // Returns whether the favicon was set in the bookmark node.
285 bool SetBookmarkFavicon(sync_api::BaseNode* sync_node,
286 const BookmarkNode* bookmark_node) const;
287
288 // Sets the favicon of the given sync node from the given bookmark node.
289 void SetSyncNodeFavicon(const BookmarkNode* bookmark_node,
290 sync_api::WriteNode* sync_node) const;
291
292 // Helper function to determine the appropriate insertion index of sync node
293 // |node| under the Bookmark model node |parent|, to make the positions
294 // match up between the two models. This presumes that the predecessor of the
295 // item (in the bookmark model) has already been moved into its appropriate
296 // position.
297 int CalculateBookmarkModelInsertionIndex(
298 const BookmarkNode* parent,
299 const sync_api::BaseNode* node) const;
300
301 // Helper function used to fix the position of a sync node so that it matches
302 // the position of a corresponding bookmark model node. |parent| and
303 // |index| identify the bookmark model position. |dst| is the node whose
304 // position is to be fixed. If |operation| is CREATE, treat |dst| as an
305 // uncreated node and set its position via InitByCreation(); otherwise,
306 // |dst| is treated as an existing node, and its position will be set via
307 // SetPosition(). |trans| is the transaction to which |dst| belongs. Returns
308 // false on failure.
309 bool PlaceSyncNode(MoveOrCreate operation,
310 const BookmarkNode* parent,
311 int index,
312 sync_api::WriteTransaction* trans,
313 sync_api::WriteNode* dst);
314
315 // Copy properties (but not position) from |src| to |dst|.
316 void UpdateSyncNodeProperties(const BookmarkNode* src,
317 sync_api::WriteNode* dst);
318
319 // Helper function to encode a bookmark's favicon into a PNG byte vector.
320 void EncodeFavicon(const BookmarkNode* src,
321 std::vector<unsigned char>* dst) const;
322
323 // Remove the sync node corresponding to |node|. It shouldn't have
324 // any children.
325 void RemoveOneSyncNode(sync_api::WriteTransaction* trans,
326 const BookmarkNode* node);
327
328 // Remove all the sync nodes associated with |node| and its children.
329 void RemoveSyncNodeHierarchy(const BookmarkNode* node);
330
331 // Whether the sync merge warning should be shown.
332 bool MergeAndSyncAcceptanceNeeded() const;
333
334 // Sets the last synced time to the current time.
335 void UpdateLastSyncedTime();
336
[email protected]1f97a112009-08-11 02:17:06337 // Time at which error UI is presented for the NTP.
338 base::TimeTicks auth_error_time_;
339
[email protected]132c85652009-08-05 01:18:27340 // The profile whose data we are synchronizing.
341 Profile* profile_;
342
343 // TODO(ncarter): Put this in a profile, once there is UI for it.
344 // This specifies where to find the sync server.
345 GURL sync_service_url_;
346
347 // Model assocation manager instance.
348 scoped_refptr<browser_sync::ModelAssociator> model_associator_;
349
350 // The last time we detected a successful transition from SYNCING state.
351 // Our backend notifies us whenever we should take a new snapshot.
352 base::Time last_synced_time_;
353
354 // Our asynchronous backend to communicate with sync components living on
355 // other threads.
356 scoped_ptr<browser_sync::SyncBackendHost> backend_;
357
358 // Whether the SyncBackendHost has been initialized.
359 bool backend_initialized_;
360
361 // Set to true when the user first enables sync, and we are waiting for
362 // syncapi to give us the green light on providing credentials for the first
363 // time. It is set back to false as soon as we get this message, and is
364 // false all other times so we don't have to persist this value as it will
365 // get initialized to false.
366 // TODO(timsteele): Remove this by way of starting the wizard when enabling
367 // sync *before* initializing the backend. syncapi will need to change, but
368 // it means we don't have to wait for the first AuthError; if we ever get
369 // one, it is actually an error and this bool isn't needed.
370 bool expecting_first_run_auth_needed_event_;
371
372 // Various pieces of UI query this value to determine if they should show
373 // an "Authenticating.." type of message. We are the only central place
374 // all auth attempts funnel through, so it makes sense to provide this.
375 // As its name suggests, this should NOT be used for anything other than UI.
376 bool is_auth_in_progress_;
377
378 // True only after all bootstrapping has succeeded: the bookmark model is
379 // loaded, the sync backend is initialized, and the two domains are
380 // consistent with one another.
381 bool ready_to_process_changes_;
382
383 // True if an unrecoverable error (e.g. violation of an assumed invariant)
384 // occurred during syncer operation. This value should be checked before
385 // doing any work that might corrupt things further.
386 bool unrecoverable_error_detected_;
387
388 SyncSetupWizard wizard_;
389
390 ObserverList<Observer> observers_;
391
392 DISALLOW_COPY_AND_ASSIGN(ProfileSyncService);
393};
394
395#endif // CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_H_
396
397#endif // CHROME_PERSONALIZATION