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