Home | History | Annotate | Download | only in synced_notifications_private
      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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    138 SyncedNotificationsShim::~SyncedNotificationsShim() {
    139 }
    140 
    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 
    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 
    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 
    188 syncer::SyncDataList SyncedNotificationsShim::GetAllSyncData(
    189       syncer::ModelType type) const {
    190   NOTIMPLEMENTED();
    191   return syncer::SyncDataList();
    192 }
    193 
    194 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 
    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 
    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 
    254 bool SyncedNotificationsShim::IsSyncReady() const {
    255   return notifications_change_processor_ && app_info_change_processor_;
    256 }
    257