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.
5 #include "chrome/browser/ui/webui/sync_internals_message_handler.h"
9 #include "base/logging.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/sync/profile_sync_service.h"
12 #include "chrome/browser/sync/profile_sync_service_factory.h"
13 #include "chrome/common/channel_info.h"
14 #include "components/sync_driver/about_sync_util.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/web_ui.h"
17 #include "sync/internal_api/public/events/protocol_event.h"
18 #include "sync/internal_api/public/sessions/commit_counters.h"
19 #include "sync/internal_api/public/sessions/status_counters.h"
20 #include "sync/internal_api/public/sessions/update_counters.h"
21 #include "sync/internal_api/public/util/weak_handle.h"
22 #include "sync/js/js_event_details.h"
24 using syncer::JsEventDetails
;
25 using syncer::ModelTypeSet
;
26 using syncer::WeakHandle
;
28 SyncInternalsMessageHandler::SyncInternalsMessageHandler()
29 : is_registered_(false),
30 is_registered_for_counters_(false),
31 weak_ptr_factory_(this) {
34 SyncInternalsMessageHandler::~SyncInternalsMessageHandler() {
36 js_controller_
->RemoveJsEventHandler(this);
38 ProfileSyncService
* service
= GetProfileSyncService();
39 if (service
&& service
->HasObserver(this)) {
40 service
->RemoveObserver(this);
41 service
->RemoveProtocolEventObserver(this);
44 if (service
&& is_registered_for_counters_
) {
45 service
->RemoveTypeDebugInfoObserver(this);
49 void SyncInternalsMessageHandler::RegisterMessages() {
50 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
52 web_ui()->RegisterMessageCallback(
54 base::Bind(&SyncInternalsMessageHandler::HandleRegisterForEvents
,
55 base::Unretained(this)));
57 web_ui()->RegisterMessageCallback(
58 "registerForPerTypeCounters",
59 base::Bind(&SyncInternalsMessageHandler::HandleRegisterForPerTypeCounters
,
60 base::Unretained(this)));
62 web_ui()->RegisterMessageCallback(
63 "requestUpdatedAboutInfo",
64 base::Bind(&SyncInternalsMessageHandler::HandleRequestUpdatedAboutInfo
,
65 base::Unretained(this)));
67 web_ui()->RegisterMessageCallback(
69 base::Bind(&SyncInternalsMessageHandler::HandleRequestListOfTypes
,
70 base::Unretained(this)));
72 web_ui()->RegisterMessageCallback(
74 base::Bind(&SyncInternalsMessageHandler::HandleGetAllNodes
,
75 base::Unretained(this)));
78 void SyncInternalsMessageHandler::HandleRegisterForEvents(
79 const base::ListValue
* args
) {
80 DCHECK(args
->empty());
82 // is_registered_ flag protects us from double-registering. This could
83 // happen on a page refresh, where the JavaScript gets re-run but the
84 // message handler remains unchanged.
85 ProfileSyncService
* service
= GetProfileSyncService();
86 if (service
&& !is_registered_
) {
87 service
->AddObserver(this);
88 service
->AddProtocolEventObserver(this);
89 js_controller_
= service
->GetJsController();
90 js_controller_
->AddJsEventHandler(this);
91 is_registered_
= true;
95 void SyncInternalsMessageHandler::HandleRegisterForPerTypeCounters(
96 const base::ListValue
* args
) {
97 DCHECK(args
->empty());
99 if (ProfileSyncService
* service
= GetProfileSyncService()) {
100 if (!is_registered_for_counters_
) {
101 service
->AddTypeDebugInfoObserver(this);
102 is_registered_for_counters_
= true;
104 // Re-register to ensure counters get re-emitted.
105 service
->RemoveTypeDebugInfoObserver(this);
106 service
->AddTypeDebugInfoObserver(this);
111 void SyncInternalsMessageHandler::HandleRequestUpdatedAboutInfo(
112 const base::ListValue
* args
) {
113 DCHECK(args
->empty());
117 void SyncInternalsMessageHandler::HandleRequestListOfTypes(
118 const base::ListValue
* args
) {
119 DCHECK(args
->empty());
120 base::DictionaryValue event_details
;
121 scoped_ptr
<base::ListValue
> type_list(new base::ListValue());
122 ModelTypeSet protocol_types
= syncer::ProtocolTypes();
123 for (ModelTypeSet::Iterator it
= protocol_types
.First();
124 it
.Good(); it
.Inc()) {
125 type_list
->Append(new base::StringValue(ModelTypeToString(it
.Get())));
127 event_details
.Set("types", type_list
.release());
128 web_ui()->CallJavascriptFunction(
129 "chrome.sync.dispatchEvent",
130 base::StringValue("onReceivedListOfTypes"),
134 void SyncInternalsMessageHandler::HandleGetAllNodes(
135 const base::ListValue
* args
) {
136 DCHECK_EQ(1U, args
->GetSize());
138 bool success
= args
->GetInteger(0, &request_id
);
141 ProfileSyncService
* service
= GetProfileSyncService();
143 service
->GetAllNodes(
144 base::Bind(&SyncInternalsMessageHandler::OnReceivedAllNodes
,
145 weak_ptr_factory_
.GetWeakPtr(), request_id
));
149 void SyncInternalsMessageHandler::OnReceivedAllNodes(
151 scoped_ptr
<base::ListValue
> nodes
) {
152 base::FundamentalValue
id(request_id
);
153 web_ui()->CallJavascriptFunction("chrome.sync.getAllNodesCallback",
157 void SyncInternalsMessageHandler::OnStateChanged() {
161 void SyncInternalsMessageHandler::OnProtocolEvent(
162 const syncer::ProtocolEvent
& event
) {
163 scoped_ptr
<base::DictionaryValue
> value(
164 syncer::ProtocolEvent::ToValue(event
));
165 web_ui()->CallJavascriptFunction(
166 "chrome.sync.dispatchEvent",
167 base::StringValue("onProtocolEvent"),
171 void SyncInternalsMessageHandler::OnCommitCountersUpdated(
172 syncer::ModelType type
,
173 const syncer::CommitCounters
& counters
) {
174 EmitCounterUpdate(type
, "commit", counters
.ToValue());
177 void SyncInternalsMessageHandler::OnUpdateCountersUpdated(
178 syncer::ModelType type
,
179 const syncer::UpdateCounters
& counters
) {
180 EmitCounterUpdate(type
, "update", counters
.ToValue());
183 void SyncInternalsMessageHandler::OnStatusCountersUpdated(
184 syncer::ModelType type
,
185 const syncer::StatusCounters
& counters
) {
186 EmitCounterUpdate(type
, "status", counters
.ToValue());
189 void SyncInternalsMessageHandler::EmitCounterUpdate(
190 syncer::ModelType type
,
191 const std::string
& counter_type
,
192 scoped_ptr
<base::DictionaryValue
> value
) {
193 scoped_ptr
<base::DictionaryValue
> details(new base::DictionaryValue());
194 details
->SetString("modelType", ModelTypeToString(type
));
195 details
->SetString("counterType", counter_type
);
196 details
->Set("counters", value
.release());
197 web_ui()->CallJavascriptFunction("chrome.sync.dispatchEvent",
198 base::StringValue("onCountersUpdated"),
202 void SyncInternalsMessageHandler::HandleJsEvent(
203 const std::string
& name
,
204 const JsEventDetails
& details
) {
205 DVLOG(1) << "Handling event: " << name
206 << " with details " << details
.ToString();
207 web_ui()->CallJavascriptFunction("chrome.sync.dispatchEvent",
208 base::StringValue(name
),
212 void SyncInternalsMessageHandler::SendAboutInfo() {
213 ProfileSyncService
* sync_service
= GetProfileSyncService();
214 scoped_ptr
<base::DictionaryValue
> value
=
215 sync_ui_util::ConstructAboutInformation(sync_service
,
216 sync_service
->signin(),
217 chrome::GetChannel());
218 web_ui()->CallJavascriptFunction(
219 "chrome.sync.dispatchEvent",
220 base::StringValue("onAboutInfoUpdated"),
224 // Gets the ProfileSyncService of the underlying original profile.
225 // May return NULL (e.g., if sync is disabled on the command line).
226 ProfileSyncService
* SyncInternalsMessageHandler::GetProfileSyncService() {
227 Profile
* profile
= Profile::FromWebUI(web_ui());
228 return ProfileSyncServiceFactory::GetForProfile(
229 profile
->GetOriginalProfile());