| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/app_list/app_list_syncable_service.h" | 5 #include "chrome/browser/ui/app_list/app_list_syncable_service.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "chrome/browser/chrome_notification_types.h" | 8 #include "chrome/browser/chrome_notification_types.h" |
| 9 #include "chrome/browser/extensions/extension_prefs.h" |
| 9 #include "chrome/browser/extensions/extension_service.h" | 10 #include "chrome/browser/extensions/extension_service.h" |
| 10 #include "chrome/browser/extensions/extension_system.h" | 11 #include "chrome/browser/extensions/extension_system.h" |
| 11 #include "chrome/browser/profiles/profile.h" | 12 #include "chrome/browser/profiles/profile.h" |
| 12 #include "chrome/browser/ui/app_list/app_list_service.h" | 13 #include "chrome/browser/ui/app_list/app_list_service.h" |
| 13 #include "chrome/browser/ui/app_list/extension_app_item.h" | 14 #include "chrome/browser/ui/app_list/extension_app_item.h" |
| 14 #include "chrome/browser/ui/app_list/extension_app_model_builder.h" | 15 #include "chrome/browser/ui/app_list/extension_app_model_builder.h" |
| 15 #include "chrome/browser/ui/host_desktop.h" | 16 #include "chrome/browser/ui/host_desktop.h" |
| 16 #include "chrome/common/chrome_switches.h" | 17 #include "chrome/common/chrome_switches.h" |
| 17 #include "content/public/browser/notification_source.h" | 18 #include "content/public/browser/notification_source.h" |
| 18 #include "sync/api/sync_change_processor.h" | 19 #include "sync/api/sync_change_processor.h" |
| 19 #include "sync/api/sync_data.h" | 20 #include "sync/api/sync_data.h" |
| 20 #include "sync/api/sync_merge_result.h" | 21 #include "sync/api/sync_merge_result.h" |
| 21 #include "sync/protocol/sync.pb.h" | 22 #include "sync/protocol/sync.pb.h" |
| 23 #include "ui/app_list/app_list_folder_item.h" |
| 22 #include "ui/app_list/app_list_item.h" | 24 #include "ui/app_list/app_list_item.h" |
| 23 #include "ui/app_list/app_list_model.h" | 25 #include "ui/app_list/app_list_model.h" |
| 24 | 26 |
| 25 using syncer::SyncChange; | 27 using syncer::SyncChange; |
| 26 | 28 |
| 27 namespace app_list { | 29 namespace app_list { |
| 28 | 30 |
| 29 namespace { | 31 namespace { |
| 30 | 32 |
| 31 void UpdateSyncItemFromSync(const sync_pb::AppListSpecifics& specifics, | 33 void UpdateSyncItemFromSync(const sync_pb::AppListSpecifics& specifics, |
| 32 AppListSyncableService::SyncItem* item) { | 34 AppListSyncableService::SyncItem* item) { |
| 33 DCHECK_EQ(item->item_id, specifics.item_id()); | 35 DCHECK_EQ(item->item_id, specifics.item_id()); |
| 34 item->item_type = specifics.item_type(); | 36 item->item_type = specifics.item_type(); |
| 35 item->item_name = specifics.item_name(); | 37 item->item_name = specifics.item_name(); |
| 36 item->parent_id = specifics.parent_id(); | 38 item->parent_id = specifics.parent_id(); |
| 37 if (!specifics.page_ordinal().empty()) | 39 if (!specifics.page_ordinal().empty()) |
| 38 item->page_ordinal = syncer::StringOrdinal(specifics.page_ordinal()); | 40 item->page_ordinal = syncer::StringOrdinal(specifics.page_ordinal()); |
| 39 if (!specifics.item_ordinal().empty()) | 41 if (!specifics.item_ordinal().empty()) |
| 40 item->item_ordinal = syncer::StringOrdinal(specifics.item_ordinal()); | 42 item->item_ordinal = syncer::StringOrdinal(specifics.item_ordinal()); |
| 41 } | 43 } |
| 42 | 44 |
| 43 bool UpdateSyncItemFromAppItem(const AppListItem* app_item, | 45 bool UpdateSyncItemFromAppItem(const AppListItem* app_item, |
| 44 AppListSyncableService::SyncItem* sync_item) { | 46 AppListSyncableService::SyncItem* sync_item) { |
| 45 DCHECK_EQ(sync_item->item_id, app_item->id()); | 47 DCHECK_EQ(sync_item->item_id, app_item->id()); |
| 46 bool changed = false; | 48 bool changed = false; |
| 49 if (sync_item->item_name != app_item->title()) { |
| 50 sync_item->item_name = app_item->title(); |
| 51 changed = true; |
| 52 } |
| 47 if (!sync_item->item_ordinal.IsValid() || | 53 if (!sync_item->item_ordinal.IsValid() || |
| 48 !app_item->position().Equals(sync_item->item_ordinal)) { | 54 !app_item->position().Equals(sync_item->item_ordinal)) { |
| 49 sync_item->item_ordinal = app_item->position(); | 55 sync_item->item_ordinal = app_item->position(); |
| 50 changed = true; | 56 changed = true; |
| 51 } | 57 } |
| 52 // TODO(stevenjb): Set parent_id and page_ordinal. | 58 // TODO(stevenjb): Set parent_id and page_ordinal. |
| 53 return changed; | 59 return changed; |
| 54 } | 60 } |
| 55 | 61 |
| 56 void GetSyncSpecificsFromSyncItem(const AppListSyncableService::SyncItem* item, | 62 void GetSyncSpecificsFromSyncItem(const AppListSyncableService::SyncItem* item, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 68 | 74 |
| 69 syncer::SyncData GetSyncDataFromSyncItem( | 75 syncer::SyncData GetSyncDataFromSyncItem( |
| 70 const AppListSyncableService::SyncItem* item) { | 76 const AppListSyncableService::SyncItem* item) { |
| 71 sync_pb::EntitySpecifics specifics; | 77 sync_pb::EntitySpecifics specifics; |
| 72 GetSyncSpecificsFromSyncItem(item, specifics.mutable_app_list()); | 78 GetSyncSpecificsFromSyncItem(item, specifics.mutable_app_list()); |
| 73 return syncer::SyncData::CreateLocalData(item->item_id, | 79 return syncer::SyncData::CreateLocalData(item->item_id, |
| 74 item->item_id, | 80 item->item_id, |
| 75 specifics); | 81 specifics); |
| 76 } | 82 } |
| 77 | 83 |
| 84 bool AppIsDefault(ExtensionService* service, const std::string& id) { |
| 85 return service && service->extension_prefs()->WasInstalledByDefault(id); |
| 86 } |
| 87 |
| 88 bool AppIsPlatformApp(ExtensionService* service, const std::string& id) { |
| 89 if (!service) |
| 90 return false; |
| 91 const extensions::Extension* app = service->GetInstalledExtension(id); |
| 92 DVLOG_IF(1, !app) << "No App for ID: " << id; |
| 93 return app ? app->is_platform_app() : false; |
| 94 } |
| 95 |
| 96 void UninstallExtension(ExtensionService* service, const std::string& id) { |
| 97 if (service && service->GetInstalledExtension(id)) |
| 98 service->UninstallExtension(id, false, NULL); |
| 99 } |
| 100 |
| 78 } // namespace | 101 } // namespace |
| 79 | 102 |
| 80 // AppListSyncableService::SyncItem | 103 // AppListSyncableService::SyncItem |
| 81 | 104 |
| 82 AppListSyncableService::SyncItem::SyncItem( | 105 AppListSyncableService::SyncItem::SyncItem( |
| 83 const std::string& id, | 106 const std::string& id, |
| 84 sync_pb::AppListSpecifics::AppListItemType type) | 107 sync_pb::AppListSpecifics::AppListItemType type) |
| 85 : item_id(id), | 108 : item_id(id), |
| 86 item_type(type) { | 109 item_type(type) { |
| 87 } | 110 } |
| 88 | 111 |
| 89 AppListSyncableService::SyncItem::~SyncItem() { | 112 AppListSyncableService::SyncItem::~SyncItem() { |
| 90 } | 113 } |
| 91 | 114 |
| 92 // AppListSyncableService | 115 // AppListSyncableService |
| 93 | 116 |
| 94 AppListSyncableService::AppListSyncableService( | 117 AppListSyncableService::AppListSyncableService( |
| 95 Profile* profile, | 118 Profile* profile, |
| 96 ExtensionService* extension_service) | 119 extensions::ExtensionSystem* extension_system) |
| 97 : profile_(profile), | 120 : profile_(profile), |
| 121 extension_system_(extension_system), |
| 98 model_(new AppListModel) { | 122 model_(new AppListModel) { |
| 99 if (extension_service && extension_service->is_ready()) { | 123 if (!extension_system || !extension_system->extension_service()) { |
| 124 LOG(WARNING) << "AppListSyncableService created with no ExtensionService"; |
| 125 return; |
| 126 } |
| 127 |
| 128 if (extension_system->extension_service()->is_ready()) { |
| 100 BuildModel(); | 129 BuildModel(); |
| 101 return; | 130 return; |
| 102 } | 131 } |
| 103 | 132 |
| 104 // The extensions for this profile have not yet all been loaded. | 133 // The extensions for this profile have not yet all been loaded. |
| 105 registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY, | 134 registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY, |
| 106 content::Source<Profile>(profile)); | 135 content::Source<Profile>(profile)); |
| 107 } | 136 } |
| 108 | 137 |
| 109 AppListSyncableService::~AppListSyncableService() { | 138 AppListSyncableService::~AppListSyncableService() { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 146 } | 175 } |
| 147 | 176 |
| 148 const AppListSyncableService::SyncItem* | 177 const AppListSyncableService::SyncItem* |
| 149 AppListSyncableService::GetSyncItem(const std::string& id) const { | 178 AppListSyncableService::GetSyncItem(const std::string& id) const { |
| 150 SyncItemMap::const_iterator iter = sync_items_.find(id); | 179 SyncItemMap::const_iterator iter = sync_items_.find(id); |
| 151 if (iter != sync_items_.end()) | 180 if (iter != sync_items_.end()) |
| 152 return iter->second; | 181 return iter->second; |
| 153 return NULL; | 182 return NULL; |
| 154 } | 183 } |
| 155 | 184 |
| 156 void AppListSyncableService::AddExtensionAppItem(ExtensionAppItem* item) { | 185 void AppListSyncableService::AddItem(AppListItem* item) { |
| 157 SyncItem* sync_item = AddItem( | 186 const std::string& item_id = item->id(); |
| 158 sync_pb::AppListSpecifics_AppListItemType_TYPE_APP, item); | 187 if (item_id.empty()) { |
| 159 if (!sync_item) | 188 LOG(ERROR) << "AppListItem item with empty ID"; |
| 160 return; // Item already exists. | 189 return; |
| 161 sync_item->item_name = item->extension_name(); | 190 } |
| 191 sync_pb::AppListSpecifics::AppListItemType type; |
| 192 const char* item_type = item->GetAppType(); |
| 193 if (item_type == ExtensionAppItem::kAppType) { |
| 194 type = sync_pb::AppListSpecifics_AppListItemType_TYPE_APP; |
| 195 } else if (item_type == AppListFolderItem::kAppType) { |
| 196 type = sync_pb::AppListSpecifics_AppListItemType_TYPE_FOLDER; |
| 197 } else { |
| 198 LOG(ERROR) << "Unrecognized model type: " << item_type; |
| 199 return; |
| 200 } |
| 201 SyncItem* sync_item = FindSyncItem(item_id); |
| 202 if (sync_item) { |
| 203 // If there is an existing, non-REMOVE_DEFAULT entry, update it. |
| 204 if (sync_item->item_type != |
| 205 sync_pb::AppListSpecifics::TYPE_REMOVE_DEFAULT_APP) { |
| 206 DCHECK_EQ(sync_item->item_type, type); |
| 207 DVLOG(2) << this << ": AddItem already exists: " << sync_item->ToString(); |
| 208 UpdateItem(item); |
| 209 return; |
| 210 } |
| 211 // If there is an existing REMOVE_DEFAULT_APP entry, and the app is |
| 212 // installed as a Default app, uninstall the app instead of adding it. |
| 213 if (type == sync_pb::AppListSpecifics_AppListItemType_TYPE_APP && |
| 214 AppIsDefault(extension_system_->extension_service(), item_id)) { |
| 215 DVLOG(1) << this << ": AddItem: Uninstall: " << sync_item->ToString(); |
| 216 UninstallExtension(extension_system_->extension_service(), item_id); |
| 217 return; |
| 218 } |
| 219 // Otherwise, we are adding the app as a non-default app (i.e. an app that |
| 220 // was installed by Default and removed is getting installed explicitly by |
| 221 // the user), so delete the REMOVE_DEFAULT_APP. |
| 222 if (SyncStarted()) { |
| 223 DVLOG(2) << this << " -> SYNC DELETE: " << sync_item->ToString(); |
| 224 SyncChange sync_change(FROM_HERE, SyncChange::ACTION_DELETE, |
| 225 GetSyncDataFromSyncItem(sync_item)); |
| 226 sync_processor_->ProcessSyncChanges( |
| 227 FROM_HERE, syncer::SyncChangeList(1, sync_change)); |
| 228 } |
| 229 delete sync_item; |
| 230 sync_items_.erase(item_id); |
| 231 // Fall through. The REMOVE_DEFAULT_APP entry has been deleted, now an App |
| 232 // entry can be added as usual. |
| 233 } |
| 234 |
| 235 sync_item = CreateSyncItem(item_id, type); |
| 236 UpdateSyncItemFromAppItem(item, sync_item); |
| 237 model_->item_list()->AddItem(item); |
| 238 DVLOG(1) << this << ": AddItem: " << sync_item->ToString() << " Default: " |
| 239 << AppIsDefault(extension_system_->extension_service(), item->id()); |
| 162 SendSyncChange(sync_item, SyncChange::ACTION_ADD); | 240 SendSyncChange(sync_item, SyncChange::ACTION_ADD); |
| 163 } | 241 } |
| 164 | 242 |
| 165 void AppListSyncableService::UpdateExtensionAppItem(ExtensionAppItem* item) { | 243 void AppListSyncableService::UpdateItem(AppListItem* item) { |
| 166 SyncItem* sync_item = FindSyncItem(item->id()); | 244 SyncItem* sync_item = FindSyncItem(item->id()); |
| 167 if (!sync_item) { | 245 if (!sync_item) { |
| 168 LOG(ERROR) << "UpdateExtensionAppItem: no sync item: " << item->id(); | 246 LOG(ERROR) << "UpdateItem: no sync item: " << item->id(); |
| 169 return; | 247 return; |
| 170 } | 248 } |
| 171 bool changed = UpdateSyncItemFromAppItem(item, sync_item); | 249 bool changed = UpdateSyncItemFromAppItem(item, sync_item); |
| 172 if (sync_item->item_name != item->extension_name()) { | |
| 173 sync_item->item_name = item->extension_name(); | |
| 174 changed = true; | |
| 175 } | |
| 176 if (!changed) { | 250 if (!changed) { |
| 177 DVLOG(2) << this << " - Update: SYNC NO CHANGE: " << sync_item->ToString(); | 251 DVLOG(2) << this << " - Update: SYNC NO CHANGE: " << sync_item->ToString(); |
| 178 return; | 252 return; |
| 179 } | 253 } |
| 180 SendSyncChange(sync_item, SyncChange::ACTION_UPDATE); | 254 SendSyncChange(sync_item, SyncChange::ACTION_UPDATE); |
| 181 } | 255 } |
| 182 | 256 |
| 183 void AppListSyncableService::RemoveItem(const std::string& id) { | 257 void AppListSyncableService::RemoveItem(const std::string& id) { |
| 184 DVLOG(2) << this << ": RemoveItem: " << id.substr(0, 8); | 258 DVLOG(2) << this << ": RemoveItem: " << id.substr(0, 8); |
| 185 SyncItemMap::iterator iter = sync_items_.find(id); | 259 SyncItemMap::iterator iter = sync_items_.find(id); |
| 186 if (iter == sync_items_.end()) | 260 if (iter == sync_items_.end()) { |
| 261 DVLOG(2) << this << " : No Sync Item."; |
| 187 return; | 262 return; |
| 263 } |
| 264 // Always delete the item from the model. |
| 265 model_->item_list()->DeleteItem(id); |
| 266 |
| 267 // Check for existing RemoveDefault sync item. |
| 188 SyncItem* sync_item = iter->second; | 268 SyncItem* sync_item = iter->second; |
| 269 if (sync_item->item_type == |
| 270 sync_pb::AppListSpecifics::TYPE_REMOVE_DEFAULT_APP) { |
| 271 // RemoveDefault item exists, just return. |
| 272 DVLOG(2) << this << " : RemoveDefault Item exists."; |
| 273 return; |
| 274 } |
| 275 |
| 276 if (AppIsDefault(extension_system_->extension_service(), id)) { |
| 277 // This is a Default app; update the entry to a REMOVE_DEFAULT entry. This |
| 278 // will overwrite any existing entry for the item. |
| 279 DVLOG(2) << this << " -> SYNC UPDATE: REMOVE_DEFAULT: " |
| 280 << sync_item->item_id; |
| 281 sync_item->item_type = sync_pb::AppListSpecifics::TYPE_REMOVE_DEFAULT_APP; |
| 282 SendSyncChange(sync_item, SyncChange::ACTION_UPDATE); |
| 283 return; |
| 284 } |
| 285 |
| 286 // Existing entry is a normal entry, send a Delete sync change and remove |
| 287 // the entry. |
| 189 if (SyncStarted()) { | 288 if (SyncStarted()) { |
| 190 DVLOG(2) << this << " -> SYNC DELETE: " << sync_item->ToString(); | 289 DVLOG(2) << this << " -> SYNC DELETE: " << sync_item->ToString(); |
| 191 SyncChange sync_change(FROM_HERE, SyncChange::ACTION_DELETE, | 290 SyncChange sync_change(FROM_HERE, SyncChange::ACTION_DELETE, |
| 192 GetSyncDataFromSyncItem(sync_item)); | 291 GetSyncDataFromSyncItem(sync_item)); |
| 193 sync_processor_->ProcessSyncChanges( | 292 sync_processor_->ProcessSyncChanges( |
| 194 FROM_HERE, syncer::SyncChangeList(1, sync_change)); | 293 FROM_HERE, syncer::SyncChangeList(1, sync_change)); |
| 195 } | 294 } |
| 196 delete sync_item; | 295 delete sync_item; |
| 197 sync_items_.erase(iter); | 296 sync_items_.erase(iter); |
| 198 model_->item_list()->DeleteItem(id); | |
| 199 } | 297 } |
| 200 | 298 |
| 201 // AppListSyncableService syncer::SyncableService | 299 // AppListSyncableService syncer::SyncableService |
| 202 | 300 |
| 203 syncer::SyncMergeResult AppListSyncableService::MergeDataAndStartSyncing( | 301 syncer::SyncMergeResult AppListSyncableService::MergeDataAndStartSyncing( |
| 204 syncer::ModelType type, | 302 syncer::ModelType type, |
| 205 const syncer::SyncDataList& initial_sync_data, | 303 const syncer::SyncDataList& initial_sync_data, |
| 206 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, | 304 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, |
| 207 scoped_ptr<syncer::SyncErrorFactory> error_handler) { | 305 scoped_ptr<syncer::SyncErrorFactory> error_handler) { |
| 208 DCHECK(!sync_processor_.get()); | 306 DCHECK(!sync_processor_.get()); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 222 for (SyncItemMap::const_iterator iter = sync_items_.begin(); | 320 for (SyncItemMap::const_iterator iter = sync_items_.begin(); |
| 223 iter != sync_items_.end(); ++iter) { | 321 iter != sync_items_.end(); ++iter) { |
| 224 unsynced_items.insert(iter->first); | 322 unsynced_items.insert(iter->first); |
| 225 } | 323 } |
| 226 | 324 |
| 227 // Create SyncItem entries for initial_sync_data. | 325 // Create SyncItem entries for initial_sync_data. |
| 228 size_t new_items = 0, updated_items = 0; | 326 size_t new_items = 0, updated_items = 0; |
| 229 for (syncer::SyncDataList::const_iterator iter = initial_sync_data.begin(); | 327 for (syncer::SyncDataList::const_iterator iter = initial_sync_data.begin(); |
| 230 iter != initial_sync_data.end(); ++iter) { | 328 iter != initial_sync_data.end(); ++iter) { |
| 231 const syncer::SyncData& data = *iter; | 329 const syncer::SyncData& data = *iter; |
| 330 DVLOG(2) << this << " Initial Sync Item: " |
| 331 << data.GetSpecifics().app_list().item_id() |
| 332 << " Type: " << data.GetSpecifics().app_list().item_type(); |
| 232 DCHECK_EQ(syncer::APP_LIST, data.GetDataType()); | 333 DCHECK_EQ(syncer::APP_LIST, data.GetDataType()); |
| 233 if (CreateOrUpdateSyncItem(data.GetSpecifics().app_list())) | 334 if (ProcessSyncItem(data.GetSpecifics().app_list())) |
| 234 ++new_items; | 335 ++new_items; |
| 235 else | 336 else |
| 236 ++updated_items; | 337 ++updated_items; |
| 237 unsynced_items.erase(data.GetSpecifics().app_list().item_id()); | 338 unsynced_items.erase(data.GetSpecifics().app_list().item_id()); |
| 238 } | 339 } |
| 239 | 340 |
| 240 result.set_num_items_after_association(sync_items_.size()); | 341 result.set_num_items_after_association(sync_items_.size()); |
| 241 result.set_num_items_added(new_items); | 342 result.set_num_items_added(new_items); |
| 242 result.set_num_items_deleted(0); | 343 result.set_num_items_deleted(0); |
| 243 result.set_num_items_modified(updated_items); | 344 result.set_num_items_modified(updated_items); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 260 DCHECK_EQ(type, syncer::APP_LIST); | 361 DCHECK_EQ(type, syncer::APP_LIST); |
| 261 | 362 |
| 262 sync_processor_.reset(); | 363 sync_processor_.reset(); |
| 263 sync_error_handler_.reset(); | 364 sync_error_handler_.reset(); |
| 264 } | 365 } |
| 265 | 366 |
| 266 syncer::SyncDataList AppListSyncableService::GetAllSyncData( | 367 syncer::SyncDataList AppListSyncableService::GetAllSyncData( |
| 267 syncer::ModelType type) const { | 368 syncer::ModelType type) const { |
| 268 DCHECK_EQ(syncer::APP_LIST, type); | 369 DCHECK_EQ(syncer::APP_LIST, type); |
| 269 | 370 |
| 270 DVLOG(1) << this << "GetAllSyncData: " << sync_items_.size(); | 371 DVLOG(1) << this << ": GetAllSyncData: " << sync_items_.size(); |
| 271 syncer::SyncDataList list; | 372 syncer::SyncDataList list; |
| 272 for (SyncItemMap::const_iterator iter = sync_items_.begin(); | 373 for (SyncItemMap::const_iterator iter = sync_items_.begin(); |
| 273 iter != sync_items_.end(); ++iter) { | 374 iter != sync_items_.end(); ++iter) { |
| 274 DVLOG(2) << this << " -> SYNC: " << iter->second->ToString(); | 375 DVLOG(2) << this << " -> SYNC: " << iter->second->ToString(); |
| 275 list.push_back(GetSyncDataFromSyncItem(iter->second)); | 376 list.push_back(GetSyncDataFromSyncItem(iter->second)); |
| 276 } | 377 } |
| 277 return list; | 378 return list; |
| 278 } | 379 } |
| 279 | 380 |
| 280 syncer::SyncError AppListSyncableService::ProcessSyncChanges( | 381 syncer::SyncError AppListSyncableService::ProcessSyncChanges( |
| 281 const tracked_objects::Location& from_here, | 382 const tracked_objects::Location& from_here, |
| 282 const syncer::SyncChangeList& change_list) { | 383 const syncer::SyncChangeList& change_list) { |
| 283 if (!sync_processor_.get()) { | 384 if (!sync_processor_.get()) { |
| 284 return syncer::SyncError(FROM_HERE, | 385 return syncer::SyncError(FROM_HERE, |
| 285 syncer::SyncError::DATATYPE_ERROR, | 386 syncer::SyncError::DATATYPE_ERROR, |
| 286 "App List syncable service is not started.", | 387 "App List syncable service is not started.", |
| 287 syncer::APP_LIST); | 388 syncer::APP_LIST); |
| 288 } | 389 } |
| 289 | 390 |
| 290 // Process incoming changes first. | |
| 291 DVLOG(1) << this << ": ProcessSyncChanges: " << change_list.size(); | 391 DVLOG(1) << this << ": ProcessSyncChanges: " << change_list.size(); |
| 292 for (syncer::SyncChangeList::const_iterator iter = change_list.begin(); | 392 for (syncer::SyncChangeList::const_iterator iter = change_list.begin(); |
| 293 iter != change_list.end(); ++iter) { | 393 iter != change_list.end(); ++iter) { |
| 294 const SyncChange& change = *iter; | 394 const SyncChange& change = *iter; |
| 395 DVLOG(2) << this << " Change: " |
| 396 << change.sync_data().GetSpecifics().app_list().item_id() |
| 397 << " (" << change.change_type() << ")"; |
| 295 if (change.change_type() == SyncChange::ACTION_ADD || | 398 if (change.change_type() == SyncChange::ACTION_ADD || |
| 296 change.change_type() == SyncChange::ACTION_UPDATE) { | 399 change.change_type() == SyncChange::ACTION_UPDATE) { |
| 297 CreateOrUpdateSyncItem(change.sync_data().GetSpecifics().app_list()); | 400 ProcessSyncItem(change.sync_data().GetSpecifics().app_list()); |
| 298 } else if (change.change_type() == SyncChange::ACTION_DELETE) { | 401 } else if (change.change_type() == SyncChange::ACTION_DELETE) { |
| 299 DeleteSyncItem(change.sync_data().GetSpecifics().app_list()); | 402 DeleteSyncItem(change.sync_data().GetSpecifics().app_list()); |
| 300 } else { | 403 } else { |
| 301 LOG(ERROR) << "Invalid sync change"; | 404 LOG(ERROR) << "Invalid sync change"; |
| 302 } | 405 } |
| 303 } | 406 } |
| 304 return syncer::SyncError(); | 407 return syncer::SyncError(); |
| 305 } | 408 } |
| 306 | 409 |
| 307 // AppListSyncableService private | 410 // AppListSyncableService private |
| 308 | 411 |
| 309 void AppListSyncableService::CreateAppItemFromSyncItem(SyncItem* sync_item) { | 412 bool AppListSyncableService::ProcessSyncItem( |
| 310 if (sync_item->item_type == sync_pb::AppListSpecifics::TYPE_APP) { | 413 const sync_pb::AppListSpecifics& specifics) { |
| 311 std::string extension_id = sync_item->item_id; | 414 const std::string& item_id = specifics.item_id(); |
| 312 const ExtensionService* extension_service = | 415 if (item_id.empty()) { |
| 313 extensions::ExtensionSystem::Get(profile_)->extension_service(); | 416 LOG(ERROR) << "AppList item with empty ID"; |
| 314 const extensions::Extension* app = | 417 return false; |
| 315 extension_service->GetInstalledExtension(extension_id); | |
| 316 DVLOG_IF(1, !app) << this << "No App for ID: " << extension_id; | |
| 317 bool is_platform_app = app ? app->is_platform_app() : false; | |
| 318 ExtensionAppItem* app_item = new ExtensionAppItem( | |
| 319 profile_, | |
| 320 sync_item, | |
| 321 extension_id, | |
| 322 sync_item->item_name, | |
| 323 gfx::ImageSkia(), | |
| 324 is_platform_app); | |
| 325 model_->item_list()->AddItem(app_item); | |
| 326 return; | |
| 327 } | 418 } |
| 328 if (sync_item->item_type == | 419 SyncItem* sync_item = FindSyncItem(item_id); |
| 420 if (sync_item) { |
| 421 // If an item of the same type exists, update it. |
| 422 if (sync_item->item_type == specifics.item_type()) { |
| 423 UpdateSyncItemFromSync(specifics, sync_item); |
| 424 ProcessExistingSyncItem(sync_item); |
| 425 DVLOG(2) << this << " <- SYNC UPDATE: " << sync_item->ToString(); |
| 426 return false; |
| 427 } |
| 428 // Otherwise, one of the entries should be TYPE_REMOVE_DEFAULT_APP. |
| 429 if (sync_item->item_type != |
| 430 sync_pb::AppListSpecifics::TYPE_REMOVE_DEFAULT_APP && |
| 431 specifics.item_type() != |
| 432 sync_pb::AppListSpecifics::TYPE_REMOVE_DEFAULT_APP) { |
| 433 LOG(ERROR) << "Synced item type: " << specifics.item_type() |
| 434 << " != existing sync item type: " << sync_item->item_type |
| 435 << " Deleting item from model!"; |
| 436 model_->item_list()->DeleteItem(item_id); |
| 437 } |
| 438 DVLOG(2) << this << " - ProcessSyncItem: Delete existing entry: " |
| 439 << sync_item->ToString(); |
| 440 delete sync_item; |
| 441 sync_items_.erase(item_id); |
| 442 } |
| 443 |
| 444 sync_item = CreateSyncItem(item_id, specifics.item_type()); |
| 445 UpdateSyncItemFromSync(specifics, sync_item); |
| 446 ProcessNewSyncItem(sync_item); |
| 447 DVLOG(2) << this << " <- SYNC ADD: " << sync_item->ToString(); |
| 448 return true; |
| 449 } |
| 450 |
| 451 void AppListSyncableService::ProcessNewSyncItem(SyncItem* sync_item) { |
| 452 switch (sync_item->item_type) { |
| 453 case sync_pb::AppListSpecifics::TYPE_APP: { |
| 454 std::string extension_id = sync_item->item_id; |
| 455 bool is_platform_app = |
| 456 AppIsPlatformApp(extension_system_->extension_service(), |
| 457 extension_id); |
| 458 ExtensionAppItem* app_item = new ExtensionAppItem( |
| 459 profile_, |
| 460 sync_item, |
| 461 extension_id, |
| 462 sync_item->item_name, |
| 463 gfx::ImageSkia(), |
| 464 is_platform_app); |
| 465 model_->item_list()->AddItem(app_item); |
| 466 return; |
| 467 } |
| 468 case sync_pb::AppListSpecifics::TYPE_REMOVE_DEFAULT_APP: { |
| 469 DVLOG(1) << this << ": Uninstall: " << sync_item->ToString(); |
| 470 UninstallExtension(extension_system_->extension_service(), |
| 471 sync_item->item_id); |
| 472 return; |
| 473 } |
| 474 case sync_pb::AppListSpecifics::TYPE_FOLDER: { |
| 475 // TODO(stevenjb): Implement |
| 476 LOG(WARNING) << "TYPE_FOLDER not supported"; |
| 477 return; |
| 478 } |
| 479 case sync_pb::AppListSpecifics::TYPE_URL: { |
| 480 // TODO(stevenjb): Implement |
| 481 LOG(WARNING) << "TYPE_URL not supported"; |
| 482 return; |
| 483 } |
| 484 } |
| 485 NOTREACHED() << "Unrecoginized sync item type: " << sync_item->ToString(); |
| 486 } |
| 487 |
| 488 void AppListSyncableService::ProcessExistingSyncItem(SyncItem* sync_item) { |
| 489 if (sync_item->item_type != |
| 329 sync_pb::AppListSpecifics::TYPE_REMOVE_DEFAULT_APP) { | 490 sync_pb::AppListSpecifics::TYPE_REMOVE_DEFAULT_APP) { |
| 330 // TODO(stevenjb): Implement | 491 AppListItem* item = model_->item_list()->FindItem(sync_item->item_id); |
| 492 if (item && !item->position().Equals(sync_item->item_ordinal)) |
| 493 model_->item_list()->SetItemPosition(item, sync_item->item_ordinal); |
| 331 } | 494 } |
| 332 if (sync_item->item_type == sync_pb::AppListSpecifics::TYPE_FOLDER) { | |
| 333 // TODO(stevenjb): Implement | |
| 334 } | |
| 335 if (sync_item->item_type == sync_pb::AppListSpecifics::TYPE_URL) { | |
| 336 // TODO(stevenjb): Implement | |
| 337 } | |
| 338 LOG(ERROR) << "Unsupported type: " << sync_item->item_type; | |
| 339 } | 495 } |
| 340 | 496 |
| 341 bool AppListSyncableService::SyncStarted() { | 497 bool AppListSyncableService::SyncStarted() { |
| 342 if (sync_processor_.get()) | 498 if (sync_processor_.get()) |
| 343 return true; | 499 return true; |
| 344 if (flare_.is_null()) { | 500 if (flare_.is_null()) { |
| 345 DVLOG(2) << this << ": SyncStarted: Flare."; | 501 DVLOG(2) << this << ": SyncStarted: Flare."; |
| 346 flare_ = sync_start_util::GetFlareForSyncableService(profile_->GetPath()); | 502 flare_ = sync_start_util::GetFlareForSyncableService(profile_->GetPath()); |
| 347 flare_.Run(syncer::APP_LIST); | 503 flare_.Run(syncer::APP_LIST); |
| 348 } | 504 } |
| 349 return false; | 505 return false; |
| 350 } | 506 } |
| 351 | 507 |
| 352 AppListSyncableService::SyncItem* AppListSyncableService::AddItem( | |
| 353 sync_pb::AppListSpecifics::AppListItemType type, | |
| 354 AppListItem* app_item) { | |
| 355 const std::string& item_id = app_item->id(); | |
| 356 if (item_id.empty()) { | |
| 357 LOG(ERROR) << "AppListItem item with empty ID"; | |
| 358 return NULL; | |
| 359 } | |
| 360 bool new_item = false; | |
| 361 SyncItem* sync_item = FindOrCreateSyncItem(item_id, type, &new_item); | |
| 362 if (!new_item) { | |
| 363 DVLOG(2) << this << ": AddItem already exists: " << sync_item->ToString(); | |
| 364 return NULL; // Item already exists. | |
| 365 } | |
| 366 UpdateSyncItemFromAppItem(app_item, sync_item); | |
| 367 DVLOG(1) << this << ": AddItem: " << sync_item->ToString(); | |
| 368 model_->item_list()->AddItem(app_item); | |
| 369 return sync_item; | |
| 370 } | |
| 371 | |
| 372 void AppListSyncableService::SendSyncChange( | 508 void AppListSyncableService::SendSyncChange( |
| 373 SyncItem* sync_item, | 509 SyncItem* sync_item, |
| 374 SyncChange::SyncChangeType sync_change_type) { | 510 SyncChange::SyncChangeType sync_change_type) { |
| 375 if (!SyncStarted()) { | 511 if (!SyncStarted()) { |
| 376 DVLOG(2) << this << " - SendSyncChange: SYNC NOT STARTED: " | 512 DVLOG(2) << this << " - SendSyncChange: SYNC NOT STARTED: " |
| 377 << sync_item->ToString(); | 513 << sync_item->ToString(); |
| 378 return; | 514 return; |
| 379 } | 515 } |
| 380 if (sync_change_type == SyncChange::ACTION_ADD) | 516 if (sync_change_type == SyncChange::ACTION_ADD) |
| 381 DVLOG(2) << this << " -> SYNC ADD: " << sync_item->ToString(); | 517 DVLOG(2) << this << " -> SYNC ADD: " << sync_item->ToString(); |
| 382 else | 518 else |
| 383 DVLOG(2) << this << " -> SYNC UPDATE: " << sync_item->ToString(); | 519 DVLOG(2) << this << " -> SYNC UPDATE: " << sync_item->ToString(); |
| 384 SyncChange sync_change(FROM_HERE, sync_change_type, | 520 SyncChange sync_change(FROM_HERE, sync_change_type, |
| 385 GetSyncDataFromSyncItem(sync_item)); | 521 GetSyncDataFromSyncItem(sync_item)); |
| 386 sync_processor_->ProcessSyncChanges( | 522 sync_processor_->ProcessSyncChanges( |
| 387 FROM_HERE, syncer::SyncChangeList(1, sync_change)); | 523 FROM_HERE, syncer::SyncChangeList(1, sync_change)); |
| 388 } | 524 } |
| 389 | 525 |
| 390 AppListSyncableService::SyncItem* | 526 AppListSyncableService::SyncItem* |
| 391 AppListSyncableService::FindSyncItem(const std::string& item_id) { | 527 AppListSyncableService::FindSyncItem(const std::string& item_id) { |
| 392 SyncItemMap::iterator iter = sync_items_.find(item_id); | 528 SyncItemMap::iterator iter = sync_items_.find(item_id); |
| 393 if (iter == sync_items_.end()) | 529 if (iter == sync_items_.end()) |
| 394 return NULL; | 530 return NULL; |
| 395 return iter->second; | 531 return iter->second; |
| 396 } | 532 } |
| 397 | 533 |
| 398 AppListSyncableService::SyncItem* AppListSyncableService::FindOrCreateSyncItem( | 534 AppListSyncableService::SyncItem* |
| 535 AppListSyncableService::CreateSyncItem( |
| 399 const std::string& item_id, | 536 const std::string& item_id, |
| 400 sync_pb::AppListSpecifics::AppListItemType type, | 537 sync_pb::AppListSpecifics::AppListItemType item_type) { |
| 401 bool* new_item) { | 538 DCHECK(!ContainsKey(sync_items_, item_id)); |
| 402 SyncItem* item = FindSyncItem(item_id); | 539 SyncItem* sync_item = new SyncItem(item_id, item_type); |
| 403 if (item) { | 540 sync_items_[item_id] = sync_item; |
| 404 DCHECK(type == item->item_type); | 541 return sync_item; |
| 405 *new_item = false; | |
| 406 return item; | |
| 407 } | |
| 408 | |
| 409 item = new SyncItem(item_id, type); | |
| 410 sync_items_[item_id] = item; | |
| 411 *new_item = true; | |
| 412 return item; | |
| 413 } | |
| 414 | |
| 415 bool AppListSyncableService::CreateOrUpdateSyncItem( | |
| 416 const sync_pb::AppListSpecifics& specifics) { | |
| 417 const std::string& item_id = specifics.item_id(); | |
| 418 if (item_id.empty()) { | |
| 419 LOG(ERROR) << "CreateOrUpdate AppList item with empty ID"; | |
| 420 return false; | |
| 421 } | |
| 422 bool new_item = false; | |
| 423 SyncItem* sync_item = | |
| 424 FindOrCreateSyncItem(item_id, specifics.item_type(), &new_item); | |
| 425 DVLOG(2) << this << "CreateOrUpdateSyncItem: " << sync_item->ToString() | |
| 426 << " New: " << new_item << " Pos: " << specifics.item_ordinal(); | |
| 427 UpdateSyncItemFromSync(specifics, sync_item); | |
| 428 // Update existing item in model | |
| 429 AppListItem* item = model_->item_list()->FindItem(sync_item->item_id); | |
| 430 if (item && !item->position().Equals(sync_item->item_ordinal)) | |
| 431 model_->item_list()->SetItemPosition(item, sync_item->item_ordinal); | |
| 432 if (new_item) { | |
| 433 CreateAppItemFromSyncItem(sync_item); | |
| 434 DVLOG(2) << this << " <- SYNC ADD: " << sync_item->ToString(); | |
| 435 } else { | |
| 436 DVLOG(2) << this << " <- SYNC UPDATE: " << sync_item->ToString(); | |
| 437 } | |
| 438 return new_item; | |
| 439 } | 542 } |
| 440 | 543 |
| 441 void AppListSyncableService::DeleteSyncItem( | 544 void AppListSyncableService::DeleteSyncItem( |
| 442 const sync_pb::AppListSpecifics& specifics) { | 545 const sync_pb::AppListSpecifics& specifics) { |
| 443 const std::string& item_id = specifics.item_id(); | 546 const std::string& item_id = specifics.item_id(); |
| 444 if (item_id.empty()) { | 547 if (item_id.empty()) { |
| 445 LOG(ERROR) << "Delete AppList item with empty ID"; | 548 LOG(ERROR) << "Delete AppList item with empty ID"; |
| 446 return; | 549 return; |
| 447 } | 550 } |
| 448 DVLOG(2) << this << "DeleteSyncItem: " << item_id.substr(0, 8); | 551 DVLOG(2) << this << ": DeleteSyncItem: " << item_id.substr(0, 8); |
| 449 SyncItemMap::iterator iter = sync_items_.find(item_id); | 552 SyncItemMap::iterator iter = sync_items_.find(item_id); |
| 450 if (iter == sync_items_.end()) | 553 if (iter == sync_items_.end()) |
| 451 return; | 554 return; |
| 555 sync_pb::AppListSpecifics::AppListItemType item_type = |
| 556 iter->second->item_type; |
| 452 DVLOG(2) << this << " <- SYNC DELETE: " << iter->second->ToString(); | 557 DVLOG(2) << this << " <- SYNC DELETE: " << iter->second->ToString(); |
| 453 delete iter->second; | 558 delete iter->second; |
| 454 sync_items_.erase(iter); | 559 sync_items_.erase(iter); |
| 455 model_->item_list()->DeleteItem(item_id); | 560 if (item_type != sync_pb::AppListSpecifics::TYPE_REMOVE_DEFAULT_APP) |
| 561 model_->item_list()->DeleteItem(item_id); |
| 456 } | 562 } |
| 457 | 563 |
| 458 std::string AppListSyncableService::SyncItem::ToString() const { | 564 std::string AppListSyncableService::SyncItem::ToString() const { |
| 459 return item_id.substr(0, 8) + " [" + item_ordinal.ToDebugString() + "]"; | 565 std::string res = item_id.substr(0, 8); |
| 566 if (item_type == sync_pb::AppListSpecifics::TYPE_REMOVE_DEFAULT_APP) { |
| 567 res += " { RemoveDefault }"; |
| 568 } else { |
| 569 res += " { " + item_name + " }"; |
| 570 res += " [" + item_ordinal.ToDebugString() + "]"; |
| 571 } |
| 572 return res; |
| 460 } | 573 } |
| 461 | 574 |
| 462 } // namespace app_list | 575 } // namespace app_list |
| OLD | NEW |