Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(130)

Side by Side Diff: chrome/browser/ui/app_list/app_list_syncable_service.cc

Issue 2416133002: Implement local storage for App List in case app sync is off. (Closed)
Patch Set: method renamed Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 <utility> 7 #include <utility>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/macros.h" 10 #include "base/macros.h"
11 #include "base/memory/ptr_util.h" 11 #include "base/memory/ptr_util.h"
12 #include "base/stl_util.h" 12 #include "base/stl_util.h"
13 #include "base/strings/string_util.h" 13 #include "base/strings/string_util.h"
14 #include "build/build_config.h" 14 #include "build/build_config.h"
15 #include "chrome/browser/apps/drive/drive_app_provider.h" 15 #include "chrome/browser/apps/drive/drive_app_provider.h"
16 #include "chrome/browser/extensions/extension_service.h" 16 #include "chrome/browser/extensions/extension_service.h"
17 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/app_list/app_list_service.h" 18 #include "chrome/browser/ui/app_list/app_list_service.h"
19 #include "chrome/browser/ui/app_list/extension_app_item.h" 19 #include "chrome/browser/ui/app_list/extension_app_item.h"
20 #include "chrome/browser/ui/app_list/extension_app_model_builder.h" 20 #include "chrome/browser/ui/app_list/extension_app_model_builder.h"
21 #include "chrome/common/chrome_switches.h" 21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/extensions/extension_constants.h" 22 #include "chrome/common/extensions/extension_constants.h"
23 #include "chrome/common/pref_names.h"
23 #include "chrome/grit/generated_resources.h" 24 #include "chrome/grit/generated_resources.h"
25 #include "components/pref_registry/pref_registry_syncable.h"
24 #include "components/sync/model/sync_change_processor.h" 26 #include "components/sync/model/sync_change_processor.h"
25 #include "components/sync/model/sync_data.h" 27 #include "components/sync/model/sync_data.h"
26 #include "components/sync/model/sync_merge_result.h" 28 #include "components/sync/model/sync_merge_result.h"
27 #include "components/sync/protocol/sync.pb.h" 29 #include "components/sync/protocol/sync.pb.h"
28 #include "extensions/browser/extension_prefs.h" 30 #include "extensions/browser/extension_prefs.h"
29 #include "extensions/browser/extension_system.h" 31 #include "extensions/browser/extension_system.h"
30 #include "extensions/browser/uninstall_reason.h" 32 #include "extensions/browser/uninstall_reason.h"
31 #include "extensions/common/constants.h" 33 #include "extensions/common/constants.h"
34 #include "extensions/common/one_shot_event.h"
32 #include "ui/app_list/app_list_folder_item.h" 35 #include "ui/app_list/app_list_folder_item.h"
33 #include "ui/app_list/app_list_item.h" 36 #include "ui/app_list/app_list_item.h"
34 #include "ui/app_list/app_list_model.h" 37 #include "ui/app_list/app_list_model.h"
35 #include "ui/app_list/app_list_model_observer.h" 38 #include "ui/app_list/app_list_model_observer.h"
36 #include "ui/app_list/app_list_switches.h" 39 #include "ui/app_list/app_list_switches.h"
37 #include "ui/base/l10n/l10n_util.h" 40 #include "ui/base/l10n/l10n_util.h"
38 41
39 #if defined(OS_CHROMEOS) 42 #if defined(OS_CHROMEOS)
40 #include "chrome/browser/chromeos/arc/arc_auth_service.h" 43 #include "chrome/browser/chromeos/arc/arc_auth_service.h"
41 #include "chrome/browser/chromeos/file_manager/app_id.h" 44 #include "chrome/browser/chromeos/file_manager/app_id.h"
42 #include "chrome/browser/chromeos/genius_app/app_id.h" 45 #include "chrome/browser/chromeos/genius_app/app_id.h"
43 #include "chrome/browser/ui/app_list/arc/arc_app_item.h" 46 #include "chrome/browser/ui/app_list/arc/arc_app_item.h"
44 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h" 47 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
45 #include "chrome/browser/ui/app_list/arc/arc_app_model_builder.h" 48 #include "chrome/browser/ui/app_list/arc/arc_app_model_builder.h"
46 #endif 49 #endif
47 50
48 using syncer::SyncChange; 51 using syncer::SyncChange;
49 52
50 namespace app_list { 53 namespace app_list {
51 54
52 namespace { 55 namespace {
53 56
54 const char kOemFolderId[] = "ddb1da55-d478-4243-8642-56d3041f0263"; 57 const char kOemFolderId[] = "ddb1da55-d478-4243-8642-56d3041f0263";
55 58
59 const char kNameKey[] = "name";
60 const char kParentIdKey[] = "parent_id";
61 const char kPositionKey[] = "position";
62 const char kPinPositionKey[] = "pin_position";
63 const char kTypeKey[] = "type";
64
56 // Prefix for a sync id of a Drive app. Drive app ids are in a different 65 // Prefix for a sync id of a Drive app. Drive app ids are in a different
57 // format and have to be used because a Drive app could have only an URL 66 // format and have to be used because a Drive app could have only an URL
58 // without a matching Chrome app. To differentiate the Drive app id from 67 // without a matching Chrome app. To differentiate the Drive app id from
59 // Chrome app ids, this prefix will be added to create the sync item id 68 // Chrome app ids, this prefix will be added to create the sync item id
60 // for a Drive app item. 69 // for a Drive app item.
61 const char kDriveAppSyncIdPrefix[] = "drive-app-"; 70 const char kDriveAppSyncIdPrefix[] = "drive-app-";
62 71
63 void UpdateSyncItemFromSync(const sync_pb::AppListSpecifics& specifics, 72 void UpdateSyncItemFromSync(const sync_pb::AppListSpecifics& specifics,
64 AppListSyncableService::SyncItem* item) { 73 AppListSyncableService::SyncItem* item) {
65 DCHECK_EQ(item->item_id, specifics.item_id()); 74 DCHECK_EQ(item->item_id, specifics.item_id());
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
166 std::string GetDriveAppSyncId(const std::string& drive_app_id) { 175 std::string GetDriveAppSyncId(const std::string& drive_app_id) {
167 return kDriveAppSyncIdPrefix + drive_app_id; 176 return kDriveAppSyncIdPrefix + drive_app_id;
168 } 177 }
169 178
170 std::string GetDriveAppIdFromSyncId(const std::string& sync_id) { 179 std::string GetDriveAppIdFromSyncId(const std::string& sync_id) {
171 if (!IsDriveAppSyncId(sync_id)) 180 if (!IsDriveAppSyncId(sync_id))
172 return std::string(); 181 return std::string();
173 return sync_id.substr(strlen(kDriveAppSyncIdPrefix)); 182 return sync_id.substr(strlen(kDriveAppSyncIdPrefix));
174 } 183 }
175 184
185 void RemoveSyncItemFromLocalStorage(Profile* profile,
186 const std::string& item_id) {
187 DictionaryPrefUpdate(profile->GetPrefs(), prefs::kAppListLocalState)->
188 Remove(item_id, nullptr);
189 }
190
191 void UpdateSyncItemInLocalStorage(
192 Profile* profile,
193 const AppListSyncableService::SyncItem* sync_item) {
194 DictionaryPrefUpdate pref_update(profile->GetPrefs(),
195 prefs::kAppListLocalState);
196 base::DictionaryValue* dict_item = nullptr;
197 if (!pref_update->GetDictionaryWithoutPathExpansion(sync_item->item_id,
198 &dict_item)) {
199 dict_item = new base::DictionaryValue();
200 pref_update->SetWithoutPathExpansion(sync_item->item_id, dict_item);
201 }
202
203 dict_item->SetString(kNameKey, sync_item->item_name);
204 dict_item->SetString(kParentIdKey, sync_item->parent_id);
205 dict_item->SetString(kPositionKey,sync_item->item_ordinal.IsValid() ?
206 sync_item->item_ordinal.ToInternalValue() : std::string());
207 dict_item->SetString(kPinPositionKey, sync_item->item_pin_ordinal.IsValid() ?
208 sync_item->item_pin_ordinal.ToInternalValue() : std::string());
209 dict_item->SetInteger(kTypeKey, static_cast<int>(sync_item->item_type));
210 }
211
176 } // namespace 212 } // namespace
177 213
178 // AppListSyncableService::SyncItem 214 // AppListSyncableService::SyncItem
179 215
180 AppListSyncableService::SyncItem::SyncItem( 216 AppListSyncableService::SyncItem::SyncItem(
181 const std::string& id, 217 const std::string& id,
182 sync_pb::AppListSpecifics::AppListItemType type) 218 sync_pb::AppListSpecifics::AppListItemType type)
183 : item_id(id), 219 : item_id(id),
184 item_type(type) { 220 item_type(type) {
185 } 221 }
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 } 283 }
248 284
249 AppListSyncableService* owner_; 285 AppListSyncableService* owner_;
250 AppListItem* adding_item_; // Unowned pointer to item being added. 286 AppListItem* adding_item_; // Unowned pointer to item being added.
251 287
252 DISALLOW_COPY_AND_ASSIGN(ModelObserver); 288 DISALLOW_COPY_AND_ASSIGN(ModelObserver);
253 }; 289 };
254 290
255 // AppListSyncableService 291 // AppListSyncableService
256 292
293 // static
294 void AppListSyncableService::RegisterProfilePrefs(
295 user_prefs::PrefRegistrySyncable* registry) {
296 registry->RegisterDictionaryPref(prefs::kAppListLocalState);
297 }
298
257 AppListSyncableService::AppListSyncableService( 299 AppListSyncableService::AppListSyncableService(
258 Profile* profile, 300 Profile* profile,
259 extensions::ExtensionSystem* extension_system) 301 extensions::ExtensionSystem* extension_system)
260 : profile_(profile), 302 : profile_(profile),
261 extension_system_(extension_system), 303 extension_system_(extension_system),
262 model_(new AppListModel), 304 model_(new AppListModel),
263 initial_sync_data_processed_(false), 305 initial_sync_data_processed_(false),
264 first_app_list_sync_(true) { 306 first_app_list_sync_(true),
307 weak_ptr_factory_(this) {
265 if (!extension_system) { 308 if (!extension_system) {
266 LOG(ERROR) << "AppListSyncableService created with no ExtensionSystem"; 309 LOG(ERROR) << "AppListSyncableService created with no ExtensionSystem";
267 return; 310 return;
268 } 311 }
269 312
270 oem_folder_name_ = 313 oem_folder_name_ =
271 l10n_util::GetStringUTF8(IDS_APP_LIST_OEM_DEFAULT_FOLDER_NAME); 314 l10n_util::GetStringUTF8(IDS_APP_LIST_OEM_DEFAULT_FOLDER_NAME);
315
316 // TODO(khmel): Now we support persistent state of this service. It is
317 // possible to remove folder UI enabled check.
318 if (switches::IsFolderUIEnabled())
319 model_->SetFoldersEnabled(true);
320
321 if (IsExtensionServiceReady()) {
322 BuildModel();
323 } else {
324 extension_system_->ready().Post(
325 FROM_HERE, base::Bind(&AppListSyncableService::BuildModel,
326 weak_ptr_factory_.GetWeakPtr()));
327 }
272 } 328 }
273 329
274 AppListSyncableService::~AppListSyncableService() { 330 AppListSyncableService::~AppListSyncableService() {
275 // Remove observers. 331 // Remove observers.
276 model_observer_.reset(); 332 model_observer_.reset();
277 } 333 }
278 334
335 bool AppListSyncableService::IsExtensionServiceReady() const {
336 return extension_system_->extension_service() &&
337 extension_system_->extension_service()->is_ready();
338 }
339
340 void AppListSyncableService::InitFromLocalStorage() {
341 // This should happen before sync and model is built.
342 DCHECK(!sync_processor_.get());
343 DCHECK(!IsInitialized());
344
345 // Restore initial state from local storage.
346 const base::DictionaryValue* local_items = profile_->GetPrefs()->
347 GetDictionary(prefs::kAppListLocalState);
348 DCHECK(local_items);
349
350 for (base::DictionaryValue::Iterator item(*local_items); !item.IsAtEnd();
351 item.Advance()) {
352 const base::DictionaryValue* dict_item;
353 if (!item.value().GetAsDictionary(&dict_item)) {
354 LOG(ERROR) << "Dictionary not found for " << item.key() + ".";
355 continue;
356 }
357
358 int type;
359 if (!dict_item->GetInteger(kTypeKey, &type)) {
360 LOG(ERROR) << "Item type is not set in local storage for " << item.key()
361 << ".";
362 continue;
363 }
364
365 SyncItem* sync_item = CreateSyncItem(item.key(),
366 static_cast<sync_pb::AppListSpecifics::AppListItemType>(type));
367
368 dict_item->GetString(kNameKey, &sync_item->item_name);
369 dict_item->GetString(kParentIdKey, &sync_item->parent_id);
370 std::string position;
371 std::string pin_position;
372 dict_item->GetString(kPositionKey, &position);
373 dict_item->GetString(kPinPositionKey, &pin_position);
374 if (!position.empty())
375 sync_item->item_ordinal = syncer::StringOrdinal(position);
376 if (!pin_position.empty())
377 sync_item->item_pin_ordinal = syncer::StringOrdinal(pin_position);
378 ProcessNewSyncItem(sync_item);
379 }
380 }
381
382 bool AppListSyncableService::IsInitialized() const {
383 return apps_builder_.get();
384 }
385
279 void AppListSyncableService::BuildModel() { 386 void AppListSyncableService::BuildModel() {
387 InitFromLocalStorage();
388
280 // TODO(calamity): make this a DCHECK after a dev channel release. 389 // TODO(calamity): make this a DCHECK after a dev channel release.
281 CHECK(extension_system_->extension_service() && 390 CHECK(IsExtensionServiceReady());
282 extension_system_->extension_service()->is_ready());
283 AppListControllerDelegate* controller = NULL; 391 AppListControllerDelegate* controller = NULL;
284 AppListService* service = AppListService::Get(); 392 AppListService* service = AppListService::Get();
285 if (service) 393 if (service)
286 controller = service->GetControllerDelegate(); 394 controller = service->GetControllerDelegate();
287 apps_builder_.reset(new ExtensionAppModelBuilder(controller)); 395 apps_builder_.reset(new ExtensionAppModelBuilder(controller));
288 #if defined(OS_CHROMEOS) 396 #if defined(OS_CHROMEOS)
289 if (arc::ArcAuthService::IsAllowedForProfile(profile_)) 397 if (arc::ArcAuthService::IsAllowedForProfile(profile_))
290 arc_apps_builder_.reset(new ArcAppModelBuilder(controller)); 398 arc_apps_builder_.reset(new ArcAppModelBuilder(controller));
291 #endif 399 #endif
292 DCHECK(profile_); 400 DCHECK(profile_);
293 if (app_list::switches::IsAppListSyncEnabled()) { 401 if (app_list::switches::IsAppListSyncEnabled()) {
294 VLOG(1) << this << ": AppListSyncableService: InitializeWithService."; 402 VLOG(1) << this << ": AppListSyncableService: InitializeWithService.";
295 SyncStarted(); 403 SyncStarted();
296 apps_builder_->InitializeWithService(this, model_.get()); 404 apps_builder_->InitializeWithService(this, model_.get());
297 #if defined(OS_CHROMEOS) 405 #if defined(OS_CHROMEOS)
298 if (arc_apps_builder_.get()) 406 if (arc_apps_builder_.get())
299 arc_apps_builder_->InitializeWithService(this, model_.get()); 407 arc_apps_builder_->InitializeWithService(this, model_.get());
300 #endif 408 #endif
301 } else { 409 } else {
302 VLOG(1) << this << ": AppListSyncableService: InitializeWithProfile."; 410 VLOG(1) << this << ": AppListSyncableService: InitializeWithProfile.";
303 apps_builder_->InitializeWithProfile(profile_, model_.get()); 411 apps_builder_->InitializeWithProfile(profile_, model_.get());
304 #if defined(OS_CHROMEOS) 412 #if defined(OS_CHROMEOS)
305 if (arc_apps_builder_.get()) 413 if (arc_apps_builder_.get())
306 arc_apps_builder_->InitializeWithProfile(profile_, model_.get()); 414 arc_apps_builder_->InitializeWithProfile(profile_, model_.get());
307 #endif 415 #endif
308 } 416 }
309 417
310 if (app_list::switches::IsDriveAppsInAppListEnabled()) 418 if (app_list::switches::IsDriveAppsInAppListEnabled())
311 drive_app_provider_.reset(new DriveAppProvider(profile_, this)); 419 drive_app_provider_.reset(new DriveAppProvider(profile_, this));
420
421 HandleUpdateFinished();
312 } 422 }
313 423
314 void AppListSyncableService::AddObserverAndStart(Observer* observer) { 424 void AppListSyncableService::AddObserverAndStart(Observer* observer) {
315 observer_list_.AddObserver(observer); 425 observer_list_.AddObserver(observer);
316 SyncStarted(); 426 SyncStarted();
317 } 427 }
318 428
319 void AppListSyncableService::RemoveObserver(Observer* observer) { 429 void AppListSyncableService::RemoveObserver(Observer* observer) {
320 observer_list_.RemoveObserver(observer); 430 observer_list_.RemoveObserver(observer);
321 } 431 }
322 432
323 void AppListSyncableService::NotifyObserversSyncUpdated() { 433 void AppListSyncableService::NotifyObserversSyncUpdated() {
324 for (auto& observer : observer_list_) 434 for (auto& observer : observer_list_)
325 observer.OnSyncModelUpdated(); 435 observer.OnSyncModelUpdated();
326 } 436 }
327 437
328 size_t AppListSyncableService::GetNumSyncItemsForTest() { 438 size_t AppListSyncableService::GetNumSyncItemsForTest() {
329 // If the model isn't built yet, there will be no sync items. 439 DCHECK(IsInitialized());
330 GetModel();
331
332 return sync_items_.size(); 440 return sync_items_.size();
333 } 441 }
334 442
335 void AppListSyncableService::ResetDriveAppProviderForTest() { 443 void AppListSyncableService::ResetDriveAppProviderForTest() {
336 drive_app_provider_.reset(); 444 drive_app_provider_.reset();
337 } 445 }
338 446
339 void AppListSyncableService::Shutdown() { 447 void AppListSyncableService::Shutdown() {
340 // DriveAppProvider touches other KeyedServices in its dtor and needs be 448 // DriveAppProvider touches other KeyedServices in its dtor and needs be
341 // released in shutdown stage. 449 // released in shutdown stage.
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 } 486 }
379 487
380 void AppListSyncableService::SetOemFolderName(const std::string& name) { 488 void AppListSyncableService::SetOemFolderName(const std::string& name) {
381 oem_folder_name_ = name; 489 oem_folder_name_ = name;
382 AppListFolderItem* oem_folder = model_->FindFolderItem(kOemFolderId); 490 AppListFolderItem* oem_folder = model_->FindFolderItem(kOemFolderId);
383 if (oem_folder) 491 if (oem_folder)
384 model_->SetItemName(oem_folder, oem_folder_name_); 492 model_->SetItemName(oem_folder, oem_folder_name_);
385 } 493 }
386 494
387 AppListModel* AppListSyncableService::GetModel() { 495 AppListModel* AppListSyncableService::GetModel() {
388 if (!apps_builder_) 496 DCHECK(IsInitialized());
389 BuildModel(); 497 return model_.get();
498 }
390 499
391 return model_.get(); 500 void AppListSyncableService::HandleUpdateStarted() {
501 // Don't observe the model while processing update changes.
502 model_observer_.reset();
503 }
504
505 void AppListSyncableService::HandleUpdateFinished() {
506 // Processing an update may create folders without setting their positions.
507 // Resolve them now.
508 ResolveFolderPositions();
509
510 // Resume or start observing app list model changes.
511 model_observer_.reset(new ModelObserver(this));
512
513 NotifyObserversSyncUpdated();
392 } 514 }
393 515
394 void AppListSyncableService::AddItem(std::unique_ptr<AppListItem> app_item) { 516 void AppListSyncableService::AddItem(std::unique_ptr<AppListItem> app_item) {
395 SyncItem* sync_item = FindOrAddSyncItem(app_item.get()); 517 SyncItem* sync_item = FindOrAddSyncItem(app_item.get());
396 if (!sync_item) 518 if (!sync_item)
397 return; // Item is not valid. 519 return; // Item is not valid.
398 520
399 std::string folder_id; 521 std::string folder_id;
400 if (app_list::switches::IsFolderUIEnabled()) { 522 if (app_list::switches::IsFolderUIEnabled()) {
401 if (AppIsOem(app_item->id())) { 523 if (AppIsOem(app_item->id())) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
438 } 560 }
439 561
440 AppListSyncableService::SyncItem* 562 AppListSyncableService::SyncItem*
441 AppListSyncableService::CreateSyncItemFromAppItem(AppListItem* app_item) { 563 AppListSyncableService::CreateSyncItemFromAppItem(AppListItem* app_item) {
442 sync_pb::AppListSpecifics::AppListItemType type; 564 sync_pb::AppListSpecifics::AppListItemType type;
443 if (!GetAppListItemType(app_item, &type)) 565 if (!GetAppListItemType(app_item, &type))
444 return NULL; 566 return NULL;
445 VLOG(2) << this << " CreateSyncItemFromAppItem:" << app_item->ToDebugString(); 567 VLOG(2) << this << " CreateSyncItemFromAppItem:" << app_item->ToDebugString();
446 SyncItem* sync_item = CreateSyncItem(app_item->id(), type); 568 SyncItem* sync_item = CreateSyncItem(app_item->id(), type);
447 UpdateSyncItemFromAppItem(app_item, sync_item); 569 UpdateSyncItemFromAppItem(app_item, sync_item);
570 UpdateSyncItemInLocalStorage(profile_, sync_item);
448 SendSyncChange(sync_item, SyncChange::ACTION_ADD); 571 SendSyncChange(sync_item, SyncChange::ACTION_ADD);
449 return sync_item; 572 return sync_item;
450 } 573 }
451 574
452 syncer::StringOrdinal AppListSyncableService::GetPinPosition( 575 syncer::StringOrdinal AppListSyncableService::GetPinPosition(
453 const std::string& app_id) { 576 const std::string& app_id) {
454 SyncItem* sync_item = FindSyncItem(app_id); 577 SyncItem* sync_item = FindSyncItem(app_id);
455 if (!sync_item) 578 if (!sync_item)
456 return syncer::StringOrdinal(); 579 return syncer::StringOrdinal();
457 return sync_item->item_pin_ordinal; 580 return sync_item->item_pin_ordinal;
458 } 581 }
459 582
460 void AppListSyncableService::SetPinPosition( 583 void AppListSyncableService::SetPinPosition(
461 const std::string& app_id, 584 const std::string& app_id,
462 const syncer::StringOrdinal& item_pin_ordinal) { 585 const syncer::StringOrdinal& item_pin_ordinal) {
463 SyncItem* sync_item = FindSyncItem(app_id); 586 SyncItem* sync_item = FindSyncItem(app_id);
464 SyncChange::SyncChangeType sync_change_type; 587 SyncChange::SyncChangeType sync_change_type;
465 if (sync_item) { 588 if (sync_item) {
466 sync_change_type = SyncChange::ACTION_UPDATE; 589 sync_change_type = SyncChange::ACTION_UPDATE;
467 } else { 590 } else {
468 sync_item = CreateSyncItem(app_id, sync_pb::AppListSpecifics::TYPE_APP); 591 sync_item = CreateSyncItem(app_id, sync_pb::AppListSpecifics::TYPE_APP);
469 sync_change_type = SyncChange::ACTION_ADD; 592 sync_change_type = SyncChange::ACTION_ADD;
470 } 593 }
471 594
472 sync_item->item_pin_ordinal = item_pin_ordinal; 595 sync_item->item_pin_ordinal = item_pin_ordinal;
596 UpdateSyncItemInLocalStorage(profile_, sync_item);
473 SendSyncChange(sync_item, sync_change_type); 597 SendSyncChange(sync_item, sync_change_type);
474 } 598 }
475 599
476 void AppListSyncableService::AddOrUpdateFromSyncItem(AppListItem* app_item) { 600 void AppListSyncableService::AddOrUpdateFromSyncItem(AppListItem* app_item) {
477 // Do not create a sync item for the OEM folder here, do that in 601 // Do not create a sync item for the OEM folder here, do that in
478 // ResolveFolderPositions once the position has been resolved. 602 // ResolveFolderPositions once the position has been resolved.
479 if (app_item->id() == kOemFolderId) 603 if (app_item->id() == kOemFolderId)
480 return; 604 return;
481 605
482 SyncItem* sync_item = FindSyncItem(app_item->id()); 606 SyncItem* sync_item = FindSyncItem(app_item->id());
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
515 LOG(ERROR) << "DeleteSyncItem: no sync item: " << item_id; 639 LOG(ERROR) << "DeleteSyncItem: no sync item: " << item_id;
516 return; 640 return;
517 } 641 }
518 if (SyncStarted()) { 642 if (SyncStarted()) {
519 VLOG(2) << this << " -> SYNC DELETE: " << sync_item->ToString(); 643 VLOG(2) << this << " -> SYNC DELETE: " << sync_item->ToString();
520 SyncChange sync_change(FROM_HERE, SyncChange::ACTION_DELETE, 644 SyncChange sync_change(FROM_HERE, SyncChange::ACTION_DELETE,
521 GetSyncDataFromSyncItem(sync_item)); 645 GetSyncDataFromSyncItem(sync_item));
522 sync_processor_->ProcessSyncChanges( 646 sync_processor_->ProcessSyncChanges(
523 FROM_HERE, syncer::SyncChangeList(1, sync_change)); 647 FROM_HERE, syncer::SyncChangeList(1, sync_change));
524 } 648 }
649 RemoveSyncItemFromLocalStorage(profile_, item_id);
525 sync_items_.erase(item_id); 650 sync_items_.erase(item_id);
526 } 651 }
527 652
528 void AppListSyncableService::UpdateSyncItem(AppListItem* app_item) { 653 void AppListSyncableService::UpdateSyncItem(AppListItem* app_item) {
529 SyncItem* sync_item = FindSyncItem(app_item->id()); 654 SyncItem* sync_item = FindSyncItem(app_item->id());
530 if (!sync_item) { 655 if (!sync_item) {
531 LOG(ERROR) << "UpdateItem: no sync item: " << app_item->id(); 656 LOG(ERROR) << "UpdateItem: no sync item: " << app_item->id();
532 return; 657 return;
533 } 658 }
534 bool changed = UpdateSyncItemFromAppItem(app_item, sync_item); 659 bool changed = UpdateSyncItemFromAppItem(app_item, sync_item);
535 if (!changed) { 660 if (!changed) {
536 DVLOG(2) << this << " - Update: SYNC NO CHANGE: " << sync_item->ToString(); 661 DVLOG(2) << this << " - Update: SYNC NO CHANGE: " << sync_item->ToString();
537 return; 662 return;
538 } 663 }
664 UpdateSyncItemInLocalStorage(profile_, sync_item);
539 SendSyncChange(sync_item, SyncChange::ACTION_UPDATE); 665 SendSyncChange(sync_item, SyncChange::ACTION_UPDATE);
540 } 666 }
541 667
542 void AppListSyncableService::RemoveItem(const std::string& id) { 668 void AppListSyncableService::RemoveItem(const std::string& id) {
543 RemoveSyncItem(id); 669 RemoveSyncItem(id);
544 model_->DeleteItem(id); 670 model_->DeleteItem(id);
545 PruneEmptySyncFolders(); 671 PruneEmptySyncFolders();
546 } 672 }
547 673
548 void AppListSyncableService::RemoveUninstalledItem(const std::string& id) { 674 void AppListSyncableService::RemoveUninstalledItem(const std::string& id) {
(...skipping 30 matching lines...) Expand all
579 return; 705 return;
580 } 706 }
581 707
582 if (type == sync_pb::AppListSpecifics::TYPE_APP && 708 if (type == sync_pb::AppListSpecifics::TYPE_APP &&
583 AppIsDefault(extension_system_->extension_service(), id)) { 709 AppIsDefault(extension_system_->extension_service(), id)) {
584 // This is a Default app; update the entry to a REMOVE_DEFAULT entry. This 710 // This is a Default app; update the entry to a REMOVE_DEFAULT entry. This
585 // will overwrite any existing entry for the item. 711 // will overwrite any existing entry for the item.
586 VLOG(2) << this << " -> SYNC UPDATE: REMOVE_DEFAULT: " 712 VLOG(2) << this << " -> SYNC UPDATE: REMOVE_DEFAULT: "
587 << sync_item->item_id; 713 << sync_item->item_id;
588 sync_item->item_type = sync_pb::AppListSpecifics::TYPE_REMOVE_DEFAULT_APP; 714 sync_item->item_type = sync_pb::AppListSpecifics::TYPE_REMOVE_DEFAULT_APP;
715 UpdateSyncItemInLocalStorage(profile_, sync_item);
589 SendSyncChange(sync_item, SyncChange::ACTION_UPDATE); 716 SendSyncChange(sync_item, SyncChange::ACTION_UPDATE);
590 return; 717 return;
591 } 718 }
592 719
593 DeleteSyncItem(iter->first); 720 DeleteSyncItem(iter->first);
594 } 721 }
595 722
596 void AppListSyncableService::ResolveFolderPositions() { 723 void AppListSyncableService::ResolveFolderPositions() {
597 if (!app_list::switches::IsFolderUIEnabled()) 724 if (!app_list::switches::IsFolderUIEnabled())
598 return; 725 return;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
639 766
640 syncer::SyncMergeResult AppListSyncableService::MergeDataAndStartSyncing( 767 syncer::SyncMergeResult AppListSyncableService::MergeDataAndStartSyncing(
641 syncer::ModelType type, 768 syncer::ModelType type,
642 const syncer::SyncDataList& initial_sync_data, 769 const syncer::SyncDataList& initial_sync_data,
643 std::unique_ptr<syncer::SyncChangeProcessor> sync_processor, 770 std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
644 std::unique_ptr<syncer::SyncErrorFactory> error_handler) { 771 std::unique_ptr<syncer::SyncErrorFactory> error_handler) {
645 DCHECK(!sync_processor_.get()); 772 DCHECK(!sync_processor_.get());
646 DCHECK(sync_processor.get()); 773 DCHECK(sync_processor.get());
647 DCHECK(error_handler.get()); 774 DCHECK(error_handler.get());
648 775
649 // Ensure the model is built. 776 HandleUpdateStarted();
650 GetModel(); 777
778 // Reset local state and recreate from sync info.
779 DictionaryPrefUpdate pref_update(profile_->GetPrefs(),
780 prefs::kAppListLocalState);
781 pref_update->Clear();
651 782
652 sync_processor_ = std::move(sync_processor); 783 sync_processor_ = std::move(sync_processor);
653 sync_error_handler_ = std::move(error_handler); 784 sync_error_handler_ = std::move(error_handler);
654 if (switches::IsFolderUIEnabled())
655 model_->SetFoldersEnabled(true);
656 785
657 syncer::SyncMergeResult result = syncer::SyncMergeResult(type); 786 syncer::SyncMergeResult result = syncer::SyncMergeResult(type);
658 result.set_num_items_before_association(sync_items_.size()); 787 result.set_num_items_before_association(sync_items_.size());
659 VLOG(1) << this << ": MergeDataAndStartSyncing: " 788 VLOG(1) << this << ": MergeDataAndStartSyncing: "
660 << initial_sync_data.size(); 789 << initial_sync_data.size();
661 790
662 // Copy all sync items to |unsynced_items|. 791 // Copy all sync items to |unsynced_items|.
663 std::set<std::string> unsynced_items; 792 std::set<std::string> unsynced_items;
664 for (const auto& sync_pair : sync_items_) { 793 for (const auto& sync_pair : sync_items_) {
665 unsynced_items.insert(sync_pair.first); 794 unsynced_items.insert(sync_pair.first);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
699 // Send unsynced items. Does not affect |result|. 828 // Send unsynced items. Does not affect |result|.
700 syncer::SyncChangeList change_list; 829 syncer::SyncChangeList change_list;
701 for (std::set<std::string>::iterator iter = unsynced_items.begin(); 830 for (std::set<std::string>::iterator iter = unsynced_items.begin();
702 iter != unsynced_items.end(); ++iter) { 831 iter != unsynced_items.end(); ++iter) {
703 SyncItem* sync_item = FindSyncItem(*iter); 832 SyncItem* sync_item = FindSyncItem(*iter);
704 // Sync can cause an item to change folders, causing an unsynced folder 833 // Sync can cause an item to change folders, causing an unsynced folder
705 // item to be removed. 834 // item to be removed.
706 if (!sync_item) 835 if (!sync_item)
707 continue; 836 continue;
708 VLOG(2) << this << " -> SYNC ADD: " << sync_item->ToString(); 837 VLOG(2) << this << " -> SYNC ADD: " << sync_item->ToString();
838 UpdateSyncItemInLocalStorage(profile_, sync_item);
709 change_list.push_back(SyncChange(FROM_HERE, SyncChange::ACTION_ADD, 839 change_list.push_back(SyncChange(FROM_HERE, SyncChange::ACTION_ADD,
710 GetSyncDataFromSyncItem(sync_item))); 840 GetSyncDataFromSyncItem(sync_item)));
711 } 841 }
712 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list); 842 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
713 843
714 // Adding items may have created folders without setting their positions 844 HandleUpdateFinished();
715 // since we haven't started observing the item list yet. Resolve those.
716 ResolveFolderPositions();
717
718 // Start observing app list model changes.
719 model_observer_.reset(new ModelObserver(this));
720
721 NotifyObserversSyncUpdated();
722 845
723 return result; 846 return result;
724 } 847 }
725 848
726 void AppListSyncableService::StopSyncing(syncer::ModelType type) { 849 void AppListSyncableService::StopSyncing(syncer::ModelType type) {
727 DCHECK_EQ(type, syncer::APP_LIST); 850 DCHECK_EQ(type, syncer::APP_LIST);
728 851
729 sync_processor_.reset(); 852 sync_processor_.reset();
730 sync_error_handler_.reset(); 853 sync_error_handler_.reset();
731 model_->SetFoldersEnabled(false);
732 } 854 }
733 855
734 syncer::SyncDataList AppListSyncableService::GetAllSyncData( 856 syncer::SyncDataList AppListSyncableService::GetAllSyncData(
735 syncer::ModelType type) const { 857 syncer::ModelType type) const {
736 DCHECK_EQ(syncer::APP_LIST, type); 858 DCHECK_EQ(syncer::APP_LIST, type);
737 859
738 VLOG(1) << this << ": GetAllSyncData: " << sync_items_.size(); 860 VLOG(1) << this << ": GetAllSyncData: " << sync_items_.size();
739 syncer::SyncDataList list; 861 syncer::SyncDataList list;
740 for (auto iter = sync_items_.begin(); iter != sync_items_.end(); ++iter) { 862 for (auto iter = sync_items_.begin(); iter != sync_items_.end(); ++iter) {
741 VLOG(2) << this << " -> SYNC: " << iter->second->ToString(); 863 VLOG(2) << this << " -> SYNC: " << iter->second->ToString();
742 list.push_back(GetSyncDataFromSyncItem(iter->second.get())); 864 list.push_back(GetSyncDataFromSyncItem(iter->second.get()));
743 } 865 }
744 return list; 866 return list;
745 } 867 }
746 868
747 syncer::SyncError AppListSyncableService::ProcessSyncChanges( 869 syncer::SyncError AppListSyncableService::ProcessSyncChanges(
748 const tracked_objects::Location& from_here, 870 const tracked_objects::Location& from_here,
749 const syncer::SyncChangeList& change_list) { 871 const syncer::SyncChangeList& change_list) {
750 if (!sync_processor_.get()) { 872 if (!sync_processor_.get()) {
751 return syncer::SyncError(FROM_HERE, 873 return syncer::SyncError(FROM_HERE,
752 syncer::SyncError::DATATYPE_ERROR, 874 syncer::SyncError::DATATYPE_ERROR,
753 "App List syncable service is not started.", 875 "App List syncable service is not started.",
754 syncer::APP_LIST); 876 syncer::APP_LIST);
755 } 877 }
756 878
757 // Don't observe the model while processing incoming sync changes. 879 HandleUpdateStarted();
758 model_observer_.reset();
759 880
760 VLOG(1) << this << ": ProcessSyncChanges: " << change_list.size(); 881 VLOG(1) << this << ": ProcessSyncChanges: " << change_list.size();
761 for (syncer::SyncChangeList::const_iterator iter = change_list.begin(); 882 for (syncer::SyncChangeList::const_iterator iter = change_list.begin();
762 iter != change_list.end(); ++iter) { 883 iter != change_list.end(); ++iter) {
763 const SyncChange& change = *iter; 884 const SyncChange& change = *iter;
764 VLOG(2) << this << " Change: " 885 VLOG(2) << this << " Change: "
765 << change.sync_data().GetSpecifics().app_list().item_id() 886 << change.sync_data().GetSpecifics().app_list().item_id()
766 << " (" << change.change_type() << ")"; 887 << " (" << change.change_type() << ")";
767 if (change.change_type() == SyncChange::ACTION_ADD || 888 if (change.change_type() == SyncChange::ACTION_ADD ||
768 change.change_type() == SyncChange::ACTION_UPDATE) { 889 change.change_type() == SyncChange::ACTION_UPDATE) {
769 ProcessSyncItemSpecifics(change.sync_data().GetSpecifics().app_list()); 890 ProcessSyncItemSpecifics(change.sync_data().GetSpecifics().app_list());
770 } else if (change.change_type() == SyncChange::ACTION_DELETE) { 891 } else if (change.change_type() == SyncChange::ACTION_DELETE) {
771 DeleteSyncItemSpecifics(change.sync_data().GetSpecifics().app_list()); 892 DeleteSyncItemSpecifics(change.sync_data().GetSpecifics().app_list());
772 } else { 893 } else {
773 LOG(ERROR) << "Invalid sync change"; 894 LOG(ERROR) << "Invalid sync change";
774 } 895 }
775 } 896 }
776 897
777 // Continue observing app list model changes. 898 HandleUpdateFinished();
778 model_observer_.reset(new ModelObserver(this));
779
780 NotifyObserversSyncUpdated();
781 899
782 return syncer::SyncError(); 900 return syncer::SyncError();
783 } 901 }
784 902
785 // AppListSyncableService private 903 // AppListSyncableService private
786 904
787 bool AppListSyncableService::ProcessSyncItemSpecifics( 905 bool AppListSyncableService::ProcessSyncItemSpecifics(
788 const sync_pb::AppListSpecifics& specifics) { 906 const sync_pb::AppListSpecifics& specifics) {
789 const std::string& item_id = specifics.item_id(); 907 const std::string& item_id = specifics.item_id();
790 if (item_id.empty()) { 908 if (item_id.empty()) {
791 LOG(ERROR) << "AppList item with empty ID"; 909 LOG(ERROR) << "AppList item with empty ID";
792 return false; 910 return false;
793 } 911 }
794 SyncItem* sync_item = FindSyncItem(item_id); 912 SyncItem* sync_item = FindSyncItem(item_id);
795 if (sync_item) { 913 if (sync_item) {
796 // If an item of the same type exists, update it. 914 // If an item of the same type exists, update it.
797 if (sync_item->item_type == specifics.item_type()) { 915 if (sync_item->item_type == specifics.item_type()) {
798 UpdateSyncItemFromSync(specifics, sync_item); 916 UpdateSyncItemFromSync(specifics, sync_item);
799 ProcessExistingSyncItem(sync_item); 917 ProcessExistingSyncItem(sync_item);
918 UpdateSyncItemInLocalStorage(profile_, sync_item);
800 VLOG(2) << this << " <- SYNC UPDATE: " << sync_item->ToString(); 919 VLOG(2) << this << " <- SYNC UPDATE: " << sync_item->ToString();
801 return false; 920 return false;
802 } 921 }
803 // Otherwise, one of the entries should be TYPE_REMOVE_DEFAULT_APP. 922 // Otherwise, one of the entries should be TYPE_REMOVE_DEFAULT_APP.
804 if (sync_item->item_type != 923 if (sync_item->item_type !=
805 sync_pb::AppListSpecifics::TYPE_REMOVE_DEFAULT_APP && 924 sync_pb::AppListSpecifics::TYPE_REMOVE_DEFAULT_APP &&
806 specifics.item_type() != 925 specifics.item_type() !=
807 sync_pb::AppListSpecifics::TYPE_REMOVE_DEFAULT_APP) { 926 sync_pb::AppListSpecifics::TYPE_REMOVE_DEFAULT_APP) {
808 LOG(ERROR) << "Synced item type: " << specifics.item_type() 927 LOG(ERROR) << "Synced item type: " << specifics.item_type()
809 << " != existing sync item type: " << sync_item->item_type 928 << " != existing sync item type: " << sync_item->item_type
810 << " Deleting item from model!"; 929 << " Deleting item from model!";
811 model_->DeleteItem(item_id); 930 model_->DeleteItem(item_id);
812 } 931 }
813 VLOG(2) << this << " - ProcessSyncItem: Delete existing entry: " 932 VLOG(2) << this << " - ProcessSyncItem: Delete existing entry: "
814 << sync_item->ToString(); 933 << sync_item->ToString();
815 sync_items_.erase(item_id); 934 sync_items_.erase(item_id);
816 } 935 }
817 936
818 sync_item = CreateSyncItem(item_id, specifics.item_type()); 937 sync_item = CreateSyncItem(item_id, specifics.item_type());
819 UpdateSyncItemFromSync(specifics, sync_item); 938 UpdateSyncItemFromSync(specifics, sync_item);
820 ProcessNewSyncItem(sync_item); 939 ProcessNewSyncItem(sync_item);
940 UpdateSyncItemInLocalStorage(profile_, sync_item);
821 VLOG(2) << this << " <- SYNC ADD: " << sync_item->ToString(); 941 VLOG(2) << this << " <- SYNC ADD: " << sync_item->ToString();
822 return true; 942 return true;
823 } 943 }
824 944
825 void AppListSyncableService::ProcessNewSyncItem(SyncItem* sync_item) { 945 void AppListSyncableService::ProcessNewSyncItem(SyncItem* sync_item) {
826 VLOG(2) << "ProcessNewSyncItem: " << sync_item->ToString(); 946 VLOG(2) << "ProcessNewSyncItem: " << sync_item->ToString();
827 switch (sync_item->item_type) { 947 switch (sync_item->item_type) {
828 case sync_pb::AppListSpecifics::TYPE_APP: { 948 case sync_pb::AppListSpecifics::TYPE_APP: {
829 // New apps are added through ExtensionAppModelBuilder. 949 // New apps are added through ExtensionAppModelBuilder.
830 // TODO(stevenjb): Determine how to handle app items in sync that 950 // TODO(stevenjb): Determine how to handle app items in sync that
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
962 LOG(ERROR) << "Delete AppList item with empty ID"; 1082 LOG(ERROR) << "Delete AppList item with empty ID";
963 return; 1083 return;
964 } 1084 }
965 VLOG(2) << this << ": DeleteSyncItemSpecifics: " << item_id.substr(0, 8); 1085 VLOG(2) << this << ": DeleteSyncItemSpecifics: " << item_id.substr(0, 8);
966 auto iter = sync_items_.find(item_id); 1086 auto iter = sync_items_.find(item_id);
967 if (iter == sync_items_.end()) 1087 if (iter == sync_items_.end())
968 return; 1088 return;
969 sync_pb::AppListSpecifics::AppListItemType item_type = 1089 sync_pb::AppListSpecifics::AppListItemType item_type =
970 iter->second->item_type; 1090 iter->second->item_type;
971 VLOG(2) << this << " <- SYNC DELETE: " << iter->second->ToString(); 1091 VLOG(2) << this << " <- SYNC DELETE: " << iter->second->ToString();
1092 RemoveSyncItemFromLocalStorage(profile_, item_id);
972 sync_items_.erase(iter); 1093 sync_items_.erase(iter);
1094
973 // Only delete apps from the model. Folders will be deleted when all 1095 // Only delete apps from the model. Folders will be deleted when all
974 // children have been deleted. 1096 // children have been deleted.
975 if (item_type == sync_pb::AppListSpecifics::TYPE_APP) { 1097 if (item_type == sync_pb::AppListSpecifics::TYPE_APP) {
976 model_->DeleteItem(item_id); 1098 model_->DeleteItem(item_id);
977 } else if (item_type == sync_pb::AppListSpecifics::TYPE_REMOVE_DEFAULT_APP) { 1099 } else if (item_type == sync_pb::AppListSpecifics::TYPE_REMOVE_DEFAULT_APP) {
978 if (IsDriveAppSyncId(item_id) && drive_app_provider_) { 1100 if (IsDriveAppSyncId(item_id) && drive_app_provider_) {
979 drive_app_provider_->RemoveUninstalledDriveAppFromSync( 1101 drive_app_provider_->RemoveUninstalledDriveAppFromSync(
980 GetDriveAppIdFromSyncId(item_id)); 1102 GetDriveAppIdFromSyncId(item_id));
981 } 1103 }
982 } 1104 }
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
1069 res += " { " + item_name + " }"; 1191 res += " { " + item_name + " }";
1070 res += " [" + item_ordinal.ToDebugString() + "]"; 1192 res += " [" + item_ordinal.ToDebugString() + "]";
1071 if (!parent_id.empty()) 1193 if (!parent_id.empty())
1072 res += " <" + parent_id.substr(0, 8) + ">"; 1194 res += " <" + parent_id.substr(0, 8) + ">";
1073 res += " [" + item_pin_ordinal.ToDebugString() + "]"; 1195 res += " [" + item_pin_ordinal.ToDebugString() + "]";
1074 } 1196 }
1075 return res; 1197 return res;
1076 } 1198 }
1077 1199
1078 } // namespace app_list 1200 } // namespace app_list
OLDNEW
« no previous file with comments | « chrome/browser/ui/app_list/app_list_syncable_service.h ('k') | chrome/browser/ui/ash/chrome_launcher_prefs.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698