• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/extensions/api/synced_notifications_private/synced_notifications_shim.h"
6 
7 #include "extensions/browser/event_router.h"
8 #include "sync/api/sync_change.h"
9 #include "sync/api/sync_data.h"
10 #include "sync/api/sync_error_factory.h"
11 #include "sync/protocol/sync.pb.h"
12 
13 using namespace extensions;
14 using namespace extensions::api;
15 
16 namespace {
17 
SyncerChangeTypeToJS(syncer::SyncChange::SyncChangeType change_type)18 synced_notifications_private::ChangeType SyncerChangeTypeToJS(
19     syncer::SyncChange::SyncChangeType change_type) {
20   switch (change_type) {
21    case syncer::SyncChange::ACTION_UPDATE:
22      return synced_notifications_private::CHANGE_TYPE_UPDATED;
23    case syncer::SyncChange::ACTION_DELETE:
24      return synced_notifications_private::CHANGE_TYPE_DELETED;
25    case syncer::SyncChange::ACTION_ADD:
26      return synced_notifications_private::CHANGE_TYPE_ADDED;
27    case syncer::SyncChange::ACTION_INVALID:
28      return synced_notifications_private::CHANGE_TYPE_NONE;
29   }
30   NOTREACHED();
31   return synced_notifications_private::CHANGE_TYPE_NONE;
32 }
33 
JSDataTypeToSyncer(synced_notifications_private::SyncDataType data_type)34 syncer::ModelType JSDataTypeToSyncer(
35     synced_notifications_private::SyncDataType data_type) {
36   switch (data_type) {
37     case synced_notifications_private::SYNC_DATA_TYPE_APP_INFO:
38       return syncer::SYNCED_NOTIFICATION_APP_INFO;
39     case synced_notifications_private::SYNC_DATA_TYPE_SYNCED_NOTIFICATION:
40       return syncer::SYNCED_NOTIFICATIONS;
41     default:
42       NOTREACHED();
43       return syncer::UNSPECIFIED;
44   }
45 }
46 
SyncerModelTypeToJS(syncer::ModelType model_type)47 synced_notifications_private::SyncDataType SyncerModelTypeToJS(
48     syncer::ModelType model_type) {
49   switch (model_type) {
50     case syncer::SYNCED_NOTIFICATION_APP_INFO:
51       return synced_notifications_private::SYNC_DATA_TYPE_APP_INFO;
52     case syncer::SYNCED_NOTIFICATIONS:
53       return synced_notifications_private::SYNC_DATA_TYPE_SYNCED_NOTIFICATION;
54     default:
55       NOTREACHED();
56       return synced_notifications_private::SYNC_DATA_TYPE_NONE;
57   }
58 }
59 
BuildNewSyncUpdate(const tracked_objects::Location & from_here,const std::string & changed_notification,syncer::SyncChange * sync_change)60 bool BuildNewSyncUpdate(
61     const tracked_objects::Location& from_here,
62     const std::string& changed_notification,
63     syncer::SyncChange* sync_change) {
64   sync_pb::EntitySpecifics specifics;
65   sync_pb::SyncedNotificationSpecifics* notification_specifics =
66       specifics.mutable_synced_notification();
67   if (!notification_specifics->ParseFromArray(
68           changed_notification.c_str(), changed_notification.size())) {
69     return false;
70   }
71 
72   // TODO(synced notifications): pass the tag via the JS API.
73   const std::string& tag =
74       notification_specifics->coalesced_notification().key();
75   syncer::SyncData sync_data =
76       syncer::SyncData::CreateLocalData(tag, tag, specifics);
77   *sync_change = syncer::SyncChange(
78       from_here, syncer::SyncChange::ACTION_UPDATE, sync_data);
79   return true;
80 }
81 
BuildNewJSSyncChange(const syncer::SyncChange & change)82 linked_ptr<synced_notifications_private::SyncChange> BuildNewJSSyncChange(
83     const syncer::SyncChange& change) {
84   linked_ptr<synced_notifications_private::SyncChange> js_change =
85       make_linked_ptr<synced_notifications_private::SyncChange>(
86           new synced_notifications_private::SyncChange());
87   js_change->change_type = SyncerChangeTypeToJS(change.change_type());
88   js_change->data.datatype =
89       SyncerModelTypeToJS(change.sync_data().GetDataType());
90   if (change.sync_data().GetDataType() == syncer::SYNCED_NOTIFICATIONS) {
91     const sync_pb::SyncedNotificationSpecifics& specifics =
92         change.sync_data().GetSpecifics().synced_notification();
93     js_change->data.data_item = specifics.SerializeAsString();
94   } else {
95     DCHECK_EQ(change.sync_data().GetDataType(),
96               syncer::SYNCED_NOTIFICATION_APP_INFO);
97     const sync_pb::SyncedNotificationAppInfoSpecifics& specifics =
98         change.sync_data().GetSpecifics().synced_notification_app_info();
99     js_change->data.data_item = specifics.SerializeAsString();
100   }
101   return js_change;
102 }
103 
PopulateJSDataListFromSync(const syncer::SyncDataList & sync_data_list,std::vector<linked_ptr<synced_notifications_private::SyncData>> * js_data_list)104 bool PopulateJSDataListFromSync(
105     const syncer::SyncDataList& sync_data_list,
106     std::vector<linked_ptr<synced_notifications_private::SyncData> >*
107         js_data_list) {
108   for (size_t i = 0; i < sync_data_list.size(); ++i) {
109     linked_ptr<synced_notifications_private::SyncData> js_data(
110         new synced_notifications_private::SyncData());
111     syncer::ModelType data_type = sync_data_list[i].GetDataType();
112     js_data->datatype = SyncerModelTypeToJS(data_type);
113     if (data_type == syncer::SYNCED_NOTIFICATIONS) {
114       const sync_pb::SyncedNotificationSpecifics& specifics =
115           sync_data_list[i].GetSpecifics().synced_notification();
116       js_data->data_item = specifics.SerializeAsString();
117     } else if (data_type == syncer::SYNCED_NOTIFICATION_APP_INFO) {
118       const sync_pb::SyncedNotificationAppInfoSpecifics& specifics =
119           sync_data_list[i].GetSpecifics().synced_notification_app_info();
120       js_data->data_item = specifics.SerializeAsString();
121     } else {
122       return false;
123     }
124     js_data_list->push_back(js_data);
125   }
126   return true;
127 }
128 
129 }  // namespace
130 
SyncedNotificationsShim(const EventLauncher & event_launcher)131 SyncedNotificationsShim::SyncedNotificationsShim(
132     const EventLauncher& event_launcher)
133     : event_launcher_(event_launcher) {
134 }
135 
~SyncedNotificationsShim()136 SyncedNotificationsShim::~SyncedNotificationsShim() {
137 }
138 
MergeDataAndStartSyncing(syncer::ModelType type,const syncer::SyncDataList & initial_sync_data,scoped_ptr<syncer::SyncChangeProcessor> sync_processor,scoped_ptr<syncer::SyncErrorFactory> error_handler)139 syncer::SyncMergeResult SyncedNotificationsShim::MergeDataAndStartSyncing(
140     syncer::ModelType type,
141     const syncer::SyncDataList& initial_sync_data,
142     scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
143     scoped_ptr<syncer::SyncErrorFactory> error_handler) {
144   if (type == syncer::SYNCED_NOTIFICATIONS)
145     notifications_change_processor_ = sync_processor.Pass();
146   else if (type == syncer::SYNCED_NOTIFICATION_APP_INFO)
147     app_info_change_processor_ = sync_processor.Pass();
148   else
149     NOTREACHED();
150 
151   // Only wake up the extension if both sync data types are ready.
152   if (notifications_change_processor_ && app_info_change_processor_) {
153     scoped_ptr<Event> event(new Event(
154         synced_notifications_private::OnSyncStartup::kEventName,
155         synced_notifications_private::OnSyncStartup::Create()));
156     event_launcher_.Run(event.Pass());
157   }
158 
159   return syncer::SyncMergeResult(type);
160 }
161 
StopSyncing(syncer::ModelType type)162 void SyncedNotificationsShim::StopSyncing(syncer::ModelType type) {
163   if (type == syncer::SYNCED_NOTIFICATIONS)
164     notifications_change_processor_.reset();
165   else if (type == syncer::SYNCED_NOTIFICATION_APP_INFO)
166     app_info_change_processor_.reset();
167   else
168     NOTREACHED();
169 }
170 
ProcessSyncChanges(const tracked_objects::Location & from_here,const syncer::SyncChangeList & changes)171 syncer::SyncError SyncedNotificationsShim::ProcessSyncChanges(
172     const tracked_objects::Location& from_here,
173     const syncer::SyncChangeList& changes) {
174   std::vector<linked_ptr<synced_notifications_private::SyncChange> > js_changes;
175   for (size_t i = 0; i < changes.size(); ++i)
176     js_changes.push_back(BuildNewJSSyncChange(changes[i]));
177 
178   scoped_ptr<base::ListValue> args(
179       synced_notifications_private::OnDataChanges::Create(js_changes));
180   scoped_ptr<Event> event(new Event(
181       synced_notifications_private::OnDataChanges::kEventName, args.Pass()));
182   event_launcher_.Run(event.Pass());
183   return syncer::SyncError();
184 }
185 
GetAllSyncData(syncer::ModelType type) const186 syncer::SyncDataList SyncedNotificationsShim::GetAllSyncData(
187       syncer::ModelType type) const {
188   NOTIMPLEMENTED();
189   return syncer::SyncDataList();
190 }
191 
GetInitialData(synced_notifications_private::SyncDataType data_type,std::vector<linked_ptr<synced_notifications_private::SyncData>> * js_data_list) const192 bool SyncedNotificationsShim::GetInitialData(
193     synced_notifications_private::SyncDataType data_type,
194     std::vector<linked_ptr<synced_notifications_private::SyncData> >*
195         js_data_list) const {
196   if (!IsSyncReady())
197     return false;
198 
199   syncer::SyncDataList sync_data_list;
200   if (JSDataTypeToSyncer(data_type) == syncer::SYNCED_NOTIFICATIONS) {
201     sync_data_list = notifications_change_processor_->GetAllSyncData(
202         syncer::SYNCED_NOTIFICATIONS);
203     if (PopulateJSDataListFromSync(sync_data_list, js_data_list))
204       return true;
205   } else if (JSDataTypeToSyncer(data_type) ==
206                  syncer::SYNCED_NOTIFICATION_APP_INFO) {
207     sync_data_list = app_info_change_processor_->GetAllSyncData(
208         syncer::SYNCED_NOTIFICATION_APP_INFO);
209     if (PopulateJSDataListFromSync(sync_data_list, js_data_list))
210       return true;
211   }
212   return false;
213 }
214 
UpdateNotification(const std::string & changed_notification)215 bool SyncedNotificationsShim::UpdateNotification(
216     const std::string& changed_notification) {
217   if (!IsSyncReady())
218     return false;
219 
220   syncer::SyncChange sync_change;
221   if (!BuildNewSyncUpdate(FROM_HERE, changed_notification, &sync_change))
222     return false;
223   syncer::SyncError error = notifications_change_processor_->ProcessSyncChanges(
224       FROM_HERE,
225       syncer::SyncChangeList(1, sync_change));
226   return !error.IsSet();
227 }
228 
SetRenderContext(synced_notifications_private::RefreshRequest refresh_request,const std::string & new_context)229 bool SyncedNotificationsShim::SetRenderContext(
230     synced_notifications_private::RefreshRequest refresh_request,
231     const std::string& new_context) {
232   if (!IsSyncReady())
233     return false;
234 
235   syncer::SyncChangeProcessor::ContextRefreshStatus sync_refresh_status =
236       refresh_request ==
237               synced_notifications_private::REFRESH_REQUEST_REFRESH_NEEDED
238           ? syncer::SyncChangeProcessor::REFRESH_NEEDED
239           : syncer::SyncChangeProcessor::NO_REFRESH;
240   syncer::SyncError error =
241       notifications_change_processor_->UpdateDataTypeContext(
242           syncer::SYNCED_NOTIFICATIONS, sync_refresh_status, new_context);
243   return !error.IsSet();
244 }
245 
IsSyncReady() const246 bool SyncedNotificationsShim::IsSyncReady() const {
247   return notifications_change_processor_ && app_info_change_processor_;
248 }
249