1// Copyright 2014 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#include "chrome/browser/sync/sessions/session_data_type_controller.h"
6
7#include "base/prefs/pref_service.h"
8#include "chrome/browser/chrome_notification_types.h"
9#include "chrome/browser/profiles/profile.h"
10#include "chrome/browser/sync/glue/chrome_report_unrecoverable_error.h"
11#include "chrome/browser/sync/glue/synced_window_delegate.h"
12#include "chrome/browser/sync/sessions/synced_window_delegates_getter.h"
13#include "chrome/common/pref_names.h"
14#include "content/public/browser/browser_thread.h"
15#include "content/public/browser/notification_details.h"
16#include "content/public/browser/notification_service.h"
17#include "content/public/browser/notification_source.h"
18
19using content::BrowserThread;
20
21namespace browser_sync {
22
23SessionDataTypeController::SessionDataTypeController(
24    sync_driver::SyncApiComponentFactory* sync_factory,
25    Profile* profile,
26    SyncedWindowDelegatesGetter* synced_window_getter,
27    sync_driver::LocalDeviceInfoProvider* local_device)
28    : UIDataTypeController(
29          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
30          base::Bind(&ChromeReportUnrecoverableError),
31          syncer::SESSIONS,
32          sync_factory),
33      profile_(profile),
34      synced_window_getter_(synced_window_getter),
35      local_device_(local_device),
36      waiting_on_session_restore_(false),
37      waiting_on_local_device_info_(false) {
38  DCHECK(local_device_);
39  pref_registrar_.Init(profile->GetPrefs());
40  pref_registrar_.Add(
41      prefs::kSavingBrowserHistoryDisabled,
42      base::Bind(&SessionDataTypeController::OnSavingBrowserHistoryPrefChanged,
43                 base::Unretained(this)));
44}
45
46SessionDataTypeController::~SessionDataTypeController() {}
47
48bool SessionDataTypeController::StartModels() {
49  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
50  std::set<browser_sync::SyncedWindowDelegate*> window =
51      synced_window_getter_->GetSyncedWindowDelegates();
52  for (std::set<browser_sync::SyncedWindowDelegate*>::const_iterator i =
53      window.begin(); i != window.end(); ++i) {
54    if ((*i)->IsSessionRestoreInProgress()) {
55      notification_registrar_.Add(
56          this,
57          chrome::NOTIFICATION_SESSION_RESTORE_COMPLETE,
58          content::Source<Profile>(profile_));
59      waiting_on_session_restore_ = true;
60      break;
61    }
62  }
63
64  if (!local_device_->GetLocalDeviceInfo()) {
65    subscription_ = local_device_->RegisterOnInitializedCallback(
66        base::Bind(&SessionDataTypeController::OnLocalDeviceInfoInitialized,
67                   this));
68    waiting_on_local_device_info_ = true;
69  }
70
71  return !IsWaiting();
72}
73
74void SessionDataTypeController::StopModels() {
75  notification_registrar_.RemoveAll();
76}
77
78bool SessionDataTypeController::ReadyForStart() const {
79  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
80  return !profile_->GetPrefs()->GetBoolean(
81      prefs::kSavingBrowserHistoryDisabled);
82}
83
84bool SessionDataTypeController::IsWaiting() {
85  return waiting_on_session_restore_ || waiting_on_local_device_info_;
86}
87
88void SessionDataTypeController::MaybeCompleteLoading() {
89  if (state_ == MODEL_STARTING && !IsWaiting()) {
90    OnModelLoaded();
91  }
92}
93
94void SessionDataTypeController::Observe(
95    int type,
96    const content::NotificationSource& source,
97    const content::NotificationDetails& details) {
98  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
99  DCHECK_EQ(chrome::NOTIFICATION_SESSION_RESTORE_COMPLETE, type);
100  DCHECK_EQ(profile_, content::Source<Profile>(source).ptr());
101  notification_registrar_.RemoveAll();
102
103  waiting_on_session_restore_ = false;
104  MaybeCompleteLoading();
105}
106
107void SessionDataTypeController::OnLocalDeviceInfoInitialized() {
108  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
109  subscription_.reset();
110
111  waiting_on_local_device_info_ = false;
112  MaybeCompleteLoading();
113}
114
115void SessionDataTypeController::OnSavingBrowserHistoryPrefChanged() {
116  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
117  if (profile_->GetPrefs()->GetBoolean(prefs::kSavingBrowserHistoryDisabled)) {
118    // If history and tabs persistence is turned off then generate an
119    // unrecoverable error. SESSIONS won't be a registered type on the next
120    // Chrome restart.
121    if (state() != NOT_RUNNING && state() != STOPPING) {
122      syncer::SyncError error(
123          FROM_HERE,
124          syncer::SyncError::DATATYPE_POLICY_ERROR,
125          "History and tab saving is now disabled by policy.",
126          syncer::SESSIONS);
127      OnSingleDataTypeUnrecoverableError(error);
128    }
129  }
130}
131
132}  // namespace browser_sync
133