• 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,const base::Closure & refresh_request)131 SyncedNotificationsShim::SyncedNotificationsShim(
132     const EventLauncher& event_launcher,
133     const base::Closure& refresh_request)
134     : event_launcher_(event_launcher),
135       refresh_request_(refresh_request) {
136 }
137 
~SyncedNotificationsShim()138 SyncedNotificationsShim::~SyncedNotificationsShim() {
139 }
140 
MergeDataAndStartSyncing(syncer::ModelType type,const syncer::SyncDataList & initial_sync_data,scoped_ptr<syncer::SyncChangeProcessor> sync_processor,scoped_ptr<syncer::SyncErrorFactory> error_handler)141 syncer::SyncMergeResult SyncedNotificationsShim::MergeDataAndStartSyncing(
142     syncer::ModelType type,
143     const syncer::SyncDataList& initial_sync_data,
144     scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
145     scoped_ptr<syncer::SyncErrorFactory> error_handler) {
146   if (type == syncer::SYNCED_NOTIFICATIONS)
147     notifications_change_processor_ = sync_processor.Pass();
148   else if (type == syncer::SYNCED_NOTIFICATION_APP_INFO)
149     app_info_change_processor_ = sync_processor.Pass();
150   else
151     NOTREACHED();
152 
153   // Only wake up the extension if both sync data types are ready.
154   if (notifications_change_processor_ && app_info_change_processor_) {
155     scoped_ptr<Event> event(new Event(
156         synced_notifications_private::OnSyncStartup::kEventName,
157         synced_notifications_private::OnSyncStartup::Create()));
158     event_launcher_.Run(event.Pass());
159   }
160 
161   return syncer::SyncMergeResult(type);
162 }
163 
StopSyncing(syncer::ModelType type)164 void SyncedNotificationsShim::StopSyncing(syncer::ModelType type) {
165   if (type == syncer::SYNCED_NOTIFICATIONS)
166     notifications_change_processor_.reset();
167   else if (type == syncer::SYNCED_NOTIFICATION_APP_INFO)
168     app_info_change_processor_.reset();
169   else
170     NOTREACHED();
171 }
172 
ProcessSyncChanges(const tracked_objects::Location & from_here,const syncer::SyncChangeList & changes)173 syncer::SyncError SyncedNotificationsShim::ProcessSyncChanges(
174     const tracked_objects::Location& from_here,
175     const syncer::SyncChangeList& changes) {
176   std::vector<linked_ptr<synced_notifications_private::SyncChange> > js_changes;
177   for (size_t i = 0; i < changes.size(); ++i)
178     js_changes.push_back(BuildNewJSSyncChange(changes[i]));
179 
180   scoped_ptr<base::ListValue> args(
181       synced_notifications_private::OnDataChanges::Create(js_changes));
182   scoped_ptr<Event> event(new Event(
183       synced_notifications_private::OnDataChanges::kEventName, args.Pass()));
184   event_launcher_.Run(event.Pass());
185   return syncer::SyncError();
186 }
187 
GetAllSyncData(syncer::ModelType type) const188 syncer::SyncDataList SyncedNotificationsShim::GetAllSyncData(
189       syncer::ModelType type) const {
190   NOTIMPLEMENTED();
191   return syncer::SyncDataList();
192 }
193 
GetInitialData(synced_notifications_private::SyncDataType data_type,std::vector<linked_ptr<synced_notifications_private::SyncData>> * js_data_list) const194 bool SyncedNotificationsShim::GetInitialData(
195     synced_notifications_private::SyncDataType data_type,
196     std::vector<linked_ptr<synced_notifications_private::SyncData> >*
197         js_data_list) const {
198   if (!IsSyncReady())
199     return false;
200 
201   syncer::SyncDataList sync_data_list;
202   if (JSDataTypeToSyncer(data_type) == syncer::SYNCED_NOTIFICATIONS) {
203     sync_data_list = notifications_change_processor_->GetAllSyncData(
204         syncer::SYNCED_NOTIFICATIONS);
205     if (PopulateJSDataListFromSync(sync_data_list, js_data_list))
206       return true;
207   } else if (JSDataTypeToSyncer(data_type) ==
208                  syncer::SYNCED_NOTIFICATION_APP_INFO) {
209     sync_data_list = app_info_change_processor_->GetAllSyncData(
210         syncer::SYNCED_NOTIFICATION_APP_INFO);
211     if (PopulateJSDataListFromSync(sync_data_list, js_data_list))
212       return true;
213   }
214   return false;
215 }
216 
UpdateNotification(const std::string & changed_notification)217 bool SyncedNotificationsShim::UpdateNotification(
218     const std::string& changed_notification) {
219   if (!IsSyncReady())
220     return false;
221 
222   syncer::SyncChange sync_change;
223   if (!BuildNewSyncUpdate(FROM_HERE, changed_notification, &sync_change))
224     return false;
225   syncer::SyncError error = notifications_change_processor_->ProcessSyncChanges(
226       FROM_HERE,
227       syncer::SyncChangeList(1, sync_change));
228   return !error.IsSet();
229 }
230 
SetRenderContext(synced_notifications_private::RefreshRequest refresh_request,const std::string & new_context)231 bool SyncedNotificationsShim::SetRenderContext(
232     synced_notifications_private::RefreshRequest refresh_request,
233     const std::string& new_context) {
234   if (!IsSyncReady())
235     return false;
236 
237   syncer::SyncChangeProcessor::ContextRefreshStatus sync_refresh_status =
238       refresh_request ==
239               synced_notifications_private::REFRESH_REQUEST_REFRESH_NEEDED
240           ? syncer::SyncChangeProcessor::REFRESH_NEEDED
241           : syncer::SyncChangeProcessor::NO_REFRESH;
242   syncer::SyncError error =
243       notifications_change_processor_->UpdateDataTypeContext(
244           syncer::SYNCED_NOTIFICATIONS, sync_refresh_status, new_context);
245 
246   if (sync_refresh_status == syncer::SyncChangeProcessor::REFRESH_NEEDED &&
247       !refresh_request_.is_null()) {
248     refresh_request_.Run();
249   }
250 
251   return !error.IsSet();
252 }
253 
IsSyncReady() const254 bool SyncedNotificationsShim::IsSyncReady() const {
255   return notifications_change_processor_ && app_info_change_processor_;
256 }
257