blob: 0b2b3f83ccbcac92945e8361590fbc4ff98d90cb [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <map>
#include <memory>
#include <string>
#include "ash/public/interfaces/app_list.mojom.h"
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "build/build_config.h"
#include "chrome/browser/sync/glue/sync_start_util.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/sync/model/string_ordinal.h"
#include "components/sync/model/sync_change.h"
#include "components/sync/model/sync_change_processor.h"
#include "components/sync/model/sync_error_factory.h"
#include "components/sync/model/syncable_service.h"
#include "components/sync/protocol/app_list_specifics.pb.h"
class AppListModelUpdater;
class ArcAppModelBuilder;
class ChromeAppListItem;
class CrostiniAppModelBuilder;
class ExtensionAppModelBuilder;
class InternalAppModelBuilder;
class Profile;
namespace extensions {
class ExtensionSystem;
namespace sync_pb {
class AppListSpecifics;
namespace user_prefs {
class PrefRegistrySyncable;
namespace app_list {
// Keyed Service that owns, stores, and syncs an AppListModel for a profile.
class AppListSyncableService : public syncer::SyncableService,
public KeyedService {
struct SyncItem {
SyncItem(const std::string& id,
sync_pb::AppListSpecifics::AppListItemType type);
const std::string item_id;
sync_pb::AppListSpecifics::AppListItemType item_type;
std::string item_name;
std::string parent_id;
syncer::StringOrdinal item_ordinal;
syncer::StringOrdinal item_pin_ordinal;
std::string ToString() const;
class Observer {
// Notifies that sync model was updated.
virtual void OnSyncModelUpdated() = 0;
virtual ~Observer() = default;
// An app list model updater factory function used by tests.
using ModelUpdaterFactoryCallback =
// Sets and resets an app list model updater factory function for tests.
class ScopedModelUpdaterFactoryForTest {
explicit ScopedModelUpdaterFactoryForTest(
const ModelUpdaterFactoryCallback& factory);
ModelUpdaterFactoryCallback factory_;
using SyncItemMap = std::map<std::string, std::unique_ptr<SyncItem>>;
// Populates the model when |extension_system| is ready.
AppListSyncableService(Profile* profile,
extensions::ExtensionSystem* extension_system);
~AppListSyncableService() override;
// Registers prefs to support local storage.
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
// Adds |item| to |sync_items_| and |model_|. If a sync item already exists,
// updates the existing sync item instead.
void AddItem(std::unique_ptr<ChromeAppListItem> app_item);
// Removes sync item matching |id|.
void RemoveItem(const std::string& id);
// Removes sync item matching |id| after item uninstall.
void RemoveUninstalledItem(const std::string& id);
// Called when properties of an item may have changed, e.g. default/oem state.
void UpdateItem(const ChromeAppListItem* app_item);
// Returns the existing sync item matching |id| or NULL.
const SyncItem* GetSyncItem(const std::string& id) const;
// Sets the name of the folder for OEM apps.
void SetOemFolderName(const std::string& name);
// Returns optional pin position for the app specified by |app_id|. If app is
// not synced or does not have associated pin position then empty ordinal is
// returned.
syncer::StringOrdinal GetPinPosition(const std::string& app_id);
// Sets pin position and how it is pinned for the app specified by |app_id|.
// Empty |item_pin_ordinal| indicates that the app has no pin.
void SetPinPosition(const std::string& app_id,
const syncer::StringOrdinal& item_pin_ordinal);
// Gets the app list model updater.
AppListModelUpdater* GetModelUpdater();
// Returns true if this service was initialized.
bool IsInitialized() const;
// Registers new observers and makes sure that service is started.
void AddObserverAndStart(Observer* observer);
void RemoveObserver(Observer* observer);
Profile* profile() { return profile_; }
size_t GetNumSyncItemsForTest();
const std::string& GetOemFolderNameForTest() const {
return oem_folder_name_;
const SyncItemMap& sync_items() const { return sync_items_; }
// syncer::SyncableService
syncer::SyncMergeResult MergeDataAndStartSyncing(
syncer::ModelType type,
const syncer::SyncDataList& initial_sync_data,
std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
std::unique_ptr<syncer::SyncErrorFactory> error_handler) override;
void StopSyncing(syncer::ModelType type) override;
syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override;
syncer::SyncError ProcessSyncChanges(
const base::Location& from_here,
const syncer::SyncChangeList& change_list) override;
// KeyedService
void Shutdown() override;
class ModelUpdaterDelegate;
// Builds the model once ExtensionService is ready.
void BuildModel();
// Returns true if sync has restarted, otherwise runs |flare_|.
bool SyncStarted();
// If |app_item| matches an existing sync item, returns it. Otherwise adds
// |app_item| to |sync_items_| and returns the new item. If |app_item| is
// invalid returns NULL.
SyncItem* FindOrAddSyncItem(const ChromeAppListItem* app_item);
// Creates a sync item for |app_item| and sends an ADD SyncChange event.
SyncItem* CreateSyncItemFromAppItem(const ChromeAppListItem* app_item);
// If a sync item for |app_item| already exists, update |app_item| from the
// sync item, otherwise create a new sync item from |app_item|.
void AddOrUpdateFromSyncItem(const ChromeAppListItem* app_item);
// Either uninstalling a default app or remove the REMOVE_DEFAULT sync item.
// Returns true if the app is removed. Otherwise deletes the existing sync
// item and returns false.
bool RemoveDefaultApp(const ChromeAppListItem* item, SyncItem* sync_item);
// Deletes a sync item from |sync_items_| and sends a DELETE action.
void DeleteSyncItem(const std::string& item_id);
// Updates existing entry in |sync_items_| from |app_item|.
void UpdateSyncItem(const ChromeAppListItem* app_item);
// Removes sync item matching |id|.
void RemoveSyncItem(const std::string& id);
// Updates folder items that may get created during initial sync.
void ResolveFolderPositions();
// Removes any empty SyncItem folders and deletes them from sync. Called
// after a sync item is removed (which may result in an empty folder).
void PruneEmptySyncFolders();
// Creates or updates a SyncItem from |specifics|. Returns true if a new item
// was created.
bool ProcessSyncItemSpecifics(const sync_pb::AppListSpecifics& specifics);
// Handles a newly created sync item (e.g. creates a new AppItem and adds it
// to the model or uninstalls a deleted default item.
void ProcessNewSyncItem(SyncItem* sync_item);
// Handles an existing sync item.
void ProcessExistingSyncItem(SyncItem* sync_item);
// Sends ADD or CHANGED for sync item.
void SendSyncChange(SyncItem* sync_item,
syncer::SyncChange::SyncChangeType sync_change_type);
// Returns an existing SyncItem corresponding to |item_id| or NULL.
SyncItem* FindSyncItem(const std::string& item_id);
// Creates a new sync item for |item_id|.
SyncItem* CreateSyncItem(
const std::string& item_id,
sync_pb::AppListSpecifics::AppListItemType item_type);
// Deletes a SyncItem matching |specifics|.
void DeleteSyncItemSpecifics(const sync_pb::AppListSpecifics& specifics);
// Gets the preferred location for the OEM folder. It may return an invalid
// position and the final OEM folder position will be determined in the
// AppListModel.
syncer::StringOrdinal GetPreferredOemFolderPos();
// Returns true if an extension matching |id| exists and was installed by
// an OEM (extension->was_installed_by_oem() is true).
bool AppIsOem(const std::string& id);
// Initializes sync items from the local storage while sync service is not
// enabled.
void InitFromLocalStorage();
// Helper that notifies observers that sync model has been updated.
void NotifyObserversSyncUpdated();
// Handles model update start/finish.
void HandleUpdateStarted();
void HandleUpdateFinished();
// Returns true if extension service is ready.
bool IsExtensionServiceReady() const;
// Remove sync data of Drive apps.
// TODO( Remove after M65 goes stable.
void RemoveDriveAppItems();
// Returns a list of sync items sorted by item ordinal.
std::vector<SyncItem*> GetSortedTopLevelSyncItems() const;
// Remove leading, trailing and duplicate "page break" items in sorted top
// level item list.
void PruneRedundantPageBreakItems();
Profile* profile_;
extensions::ExtensionSystem* extension_system_;
std::unique_ptr<AppListModelUpdater> model_updater_;
std::unique_ptr<ModelUpdaterDelegate> model_updater_delegate_;
std::unique_ptr<ExtensionAppModelBuilder> apps_builder_;
std::unique_ptr<ArcAppModelBuilder> arc_apps_builder_;
std::unique_ptr<CrostiniAppModelBuilder> crostini_apps_builder_;
std::unique_ptr<InternalAppModelBuilder> internal_apps_builder_;
std::unique_ptr<syncer::SyncChangeProcessor> sync_processor_;
std::unique_ptr<syncer::SyncErrorFactory> sync_error_handler_;
SyncItemMap sync_items_;
syncer::SyncableService::StartSyncFlare flare_;
bool initial_sync_data_processed_;
bool first_app_list_sync_;
std::string oem_folder_name_;
// List of observers.
base::ObserverList<Observer> observer_list_;
base::WeakPtrFactory<AppListSyncableService> weak_ptr_factory_;
} // namespace app_list