Add and integrate ModelTypeController into ProductSpecificationsService

Bug: b/330196800
Change-Id: I755ba69436be90b8cf72d873006792e3e1e226f3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5375240
Reviewed-by: Matthew Jones <[email protected]>
Reviewed-by: Ankush Singh <[email protected]>
Commit-Queue: David Maunder <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1275093}
diff --git a/chrome/browser/commerce/product_specifications/product_specifications_service_factory.cc b/chrome/browser/commerce/product_specifications/product_specifications_service_factory.cc
index bd5a167..032a0ed 100644
--- a/chrome/browser/commerce/product_specifications/product_specifications_service_factory.cc
+++ b/chrome/browser/commerce/product_specifications/product_specifications_service_factory.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/commerce/product_specifications/product_specifications_service_factory.h"
 
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/model_type_store_service_factory.h"
 #include "chrome/common/channel_info.h"
@@ -64,7 +66,10 @@
           ModelTypeStoreServiceFactory::GetForProfile(
               Profile::FromBrowserContext(context))
               ->GetStoreFactory(),
-          CreateChangeProcessor()));
+          CreateChangeProcessor()),
+      base::ThreadPool::CreateSequencedTaskRunner(
+          {base::MayBlock(), base::TaskPriority::USER_BLOCKING,
+           base::TaskShutdownBehavior::BLOCK_SHUTDOWN}));
 }
 
 }  // namespace commerce
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index 968d6bf..c9407c9 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -15,6 +15,7 @@
 #include "base/task/sequenced_task_runner.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
+#include "chrome/browser/commerce/product_specifications/product_specifications_service_factory.h"
 #include "chrome/browser/consent_auditor/consent_auditor_factory.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/history/history_service_factory.h"
@@ -259,7 +260,9 @@
       PowerBookmarkServiceFactory::GetForBrowserContext(profile_),
       supervised_user_settings_service,
       WebDataServiceFactory::GetPlusAddressWebDataForProfile(
-          profile_, ServiceAccessType::IMPLICIT_ACCESS));
+          profile_, ServiceAccessType::IMPLICIT_ACCESS),
+      commerce::ProductSpecificationsServiceFactory::GetForBrowserContext(
+          profile_));
 }
 
 ChromeSyncClient::~ChromeSyncClient() = default;
diff --git a/components/browser_sync/BUILD.gn b/components/browser_sync/BUILD.gn
index c2cfffb..d206286 100644
--- a/components/browser_sync/BUILD.gn
+++ b/components/browser_sync/BUILD.gn
@@ -32,6 +32,8 @@
     "//components/autofill/core/browser",
     "//components/autofill/core/common",
     "//components/bookmarks/browser",
+    "//components/commerce/core:feature_list",
+    "//components/commerce/core/product_specifications:product_specifications",
     "//components/history/core/browser",
     "//components/history/core/common",
     "//components/password_manager/core/browser",
diff --git a/components/browser_sync/DEPS b/components/browser_sync/DEPS
index f2e766e6..8855425 100644
--- a/components/browser_sync/DEPS
+++ b/components/browser_sync/DEPS
@@ -5,6 +5,7 @@
   "+components/bookmarks/common",
   "+components/bookmarks/managed",
   "+components/bookmarks/test",
+  "+components/commerce/core",
   "+components/history/core/browser",
   "+components/history/core/common",
   "+components/keyed_service/core",
diff --git a/components/browser_sync/sync_api_component_factory_impl.cc b/components/browser_sync/sync_api_component_factory_impl.cc
index 0e1a50d..1974862 100644
--- a/components/browser_sync/sync_api_component_factory_impl.cc
+++ b/components/browser_sync/sync_api_component_factory_impl.cc
@@ -27,6 +27,8 @@
 #include "components/autofill/core/browser/webdata/payments/autofill_wallet_usage_data_sync_bridge.h"
 #include "components/browser_sync/active_devices_provider_impl.h"
 #include "components/browser_sync/browser_sync_client.h"
+#include "components/commerce/core/commerce_feature_list.h"
+#include "components/commerce/core/product_specifications/product_specifications_service.h"
 #include "components/history/core/browser/sync/history_delete_directives_model_type_controller.h"
 #include "components/history/core/browser/sync/history_model_type_controller.h"
 #include "components/password_manager/core/browser/password_store/password_store_interface.h"
@@ -179,7 +181,8 @@
     supervised_user::SupervisedUserSettingsService*
         supervised_user_settings_service,
     const scoped_refptr<plus_addresses::PlusAddressWebDataService>&
-        plus_address_webdata_service)
+        plus_address_webdata_service,
+    commerce::ProductSpecificationsService* product_specifications_service)
     : sync_client_(sync_client),
       channel_(channel),
       ui_thread_(ui_thread),
@@ -197,7 +200,8 @@
       account_bookmark_sync_service_(account_bookmark_sync_service),
       power_bookmark_service_(power_bookmark_service),
       supervised_user_settings_service_(supervised_user_settings_service),
-      plus_address_webdata_service_(plus_address_webdata_service) {
+      plus_address_webdata_service_(plus_address_webdata_service),
+      product_specifications_service_(product_specifications_service) {
   DCHECK(sync_client_);
 }
 
@@ -356,6 +360,15 @@
     }
   }
 
+  if (!disabled_types.Has(syncer::COMPARE) && product_specifications_service_ &&
+      base::FeatureList::IsEnabled(commerce::kProductSpecifications)) {
+    controllers.push_back(std::make_unique<ModelTypeController>(
+        syncer::COMPARE,
+        product_specifications_service_->CreateSyncControllerDelegate(),
+        /*TODO(b/330183718) implement delegate_for_transport_mode= */
+        nullptr));
+  }
+
   if (!disabled_types.Has(syncer::HISTORY)) {
     controllers.push_back(std::make_unique<history::HistoryModelTypeController>(
         sync_service, sync_client_->GetIdentityManager(),
diff --git a/components/browser_sync/sync_api_component_factory_impl.h b/components/browser_sync/sync_api_component_factory_impl.h
index 06ae2bd..08a30ca 100644
--- a/components/browser_sync/sync_api_component_factory_impl.h
+++ b/components/browser_sync/sync_api_component_factory_impl.h
@@ -26,6 +26,10 @@
 class AutofillWebDataService;
 }
 
+namespace commerce {
+class ProductSpecificationsService;
+}
+
 namespace password_manager {
 class PasswordStoreInterface;
 }
@@ -71,7 +75,8 @@
       supervised_user::SupervisedUserSettingsService*
           supervised_user_settings_service,
       const scoped_refptr<plus_addresses::PlusAddressWebDataService>&
-          plus_address_webdata_service);
+          plus_address_webdata_service,
+      commerce::ProductSpecificationsService* product_specifications_service);
   SyncApiComponentFactoryImpl(const SyncApiComponentFactoryImpl&) = delete;
   SyncApiComponentFactoryImpl& operator=(const SyncApiComponentFactoryImpl&) =
       delete;
@@ -140,6 +145,8 @@
       supervised_user_settings_service_;
   const scoped_refptr<plus_addresses::PlusAddressWebDataService>
       plus_address_webdata_service_;
+  const raw_ptr<commerce::ProductSpecificationsService>
+      product_specifications_service_;
 };
 
 }  // namespace browser_sync
diff --git a/components/commerce/core/product_specifications/product_specifications_service.cc b/components/commerce/core/product_specifications/product_specifications_service.cc
index 0d710c5..2a673dc 100644
--- a/components/commerce/core/product_specifications/product_specifications_service.cc
+++ b/components/commerce/core/product_specifications/product_specifications_service.cc
@@ -4,12 +4,30 @@
 
 #include "components/commerce/core/product_specifications/product_specifications_service.h"
 
+#include "components/sync/model/proxy_model_type_controller_delegate.h"
+
 namespace commerce {
 
 ProductSpecificationsService::ProductSpecificationsService(
-    std::unique_ptr<ProductSpecificationsSyncBridge> bridge)
-    : bridge_(std::move(bridge)) {}
+    std::unique_ptr<ProductSpecificationsSyncBridge> bridge,
+    scoped_refptr<base::SequencedTaskRunner> backend_task_runner)
+    : bridge_(std::move(bridge)), backend_task_runner_(backend_task_runner) {}
 
 ProductSpecificationsService::~ProductSpecificationsService() = default;
 
+std::unique_ptr<syncer::ModelTypeControllerDelegate>
+ProductSpecificationsService::CreateSyncControllerDelegate() {
+  return std::make_unique<syncer::ProxyModelTypeControllerDelegate>(
+      backend_task_runner_,
+      base::BindRepeating(
+          &ProductSpecificationsService::GetSyncControllerDelegate,
+          base::Unretained(this)));
+}
+
+base::WeakPtr<syncer::ModelTypeControllerDelegate>
+ProductSpecificationsService::GetSyncControllerDelegate() {
+  CHECK(bridge_);
+  return bridge_->change_processor()->GetControllerDelegate();
+}
+
 }  // namespace commerce
diff --git a/components/commerce/core/product_specifications/product_specifications_service.h b/components/commerce/core/product_specifications/product_specifications_service.h
index eb8cab4..8c83bb2 100644
--- a/components/commerce/core/product_specifications/product_specifications_service.h
+++ b/components/commerce/core/product_specifications/product_specifications_service.h
@@ -5,24 +5,37 @@
 #ifndef COMPONENTS_COMMERCE_CORE_PRODUCT_SPECIFICATIONS_PRODUCT_SPECIFICATIONS_SERVICE_H_
 #define COMPONENTS_COMMERCE_CORE_PRODUCT_SPECIFICATIONS_PRODUCT_SPECIFICATIONS_SERVICE_H_
 
+#include "base/task/sequenced_task_runner.h"
 #include "components/commerce/core/product_specifications/product_specifications_sync_bridge.h"
 #include "components/keyed_service/core/keyed_service.h"
 
+namespace syncer {
+class ModelTypeControllerDelegate;
+}  // namespace syncer
+
 namespace commerce {
 
 // Acquires synced data about product specifications.
 class ProductSpecificationsService : public KeyedService {
  public:
-  explicit ProductSpecificationsService(
-      std::unique_ptr<ProductSpecificationsSyncBridge> bridge);
+  ProductSpecificationsService(
+      std::unique_ptr<ProductSpecificationsSyncBridge> bridge,
+      scoped_refptr<base::SequencedTaskRunner> backend_task_runner);
   ProductSpecificationsService(const ProductSpecificationsService&) = delete;
   ProductSpecificationsService& operator=(const ProductSpecificationsService&) =
       delete;
-
   ~ProductSpecificationsService() override;
 
+  // Instantiates a controller delegate to interact with
+  // ProductSpecificationsSyncBridge. Must be called from the UI thread.
+  std::unique_ptr<syncer::ModelTypeControllerDelegate>
+  CreateSyncControllerDelegate();
+
  private:
+  base::WeakPtr<syncer::ModelTypeControllerDelegate>
+  GetSyncControllerDelegate();
   std::unique_ptr<ProductSpecificationsSyncBridge> bridge_;
+  scoped_refptr<base::SequencedTaskRunner> backend_task_runner_;
 };
 
 }  // namespace commerce
diff --git a/ios/chrome/browser/sync/model/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/model/ios_chrome_sync_client.mm
index 833c25a..33e1e8e 100644
--- a/ios/chrome/browser/sync/model/ios_chrome_sync_client.mm
+++ b/ios/chrome/browser/sync/model/ios_chrome_sync_client.mm
@@ -117,7 +117,10 @@
           PowerBookmarkServiceFactory::GetForBrowserState(browser_state_),
           supervised_user_settings_service,
           ios::WebDataServiceFactory::GetPlusAddressWebDataForBrowserState(
-              browser_state_, ServiceAccessType::IMPLICIT_ACCESS));
+              browser_state_, ServiceAccessType::IMPLICIT_ACCESS),
+          /*TODO(crbug.com/330201909) implement for iOS
+             product_specifications_service= */
+          nullptr);
 
   local_data_query_helper_ =
       std::make_unique<browser_sync::LocalDataQueryHelper>(
diff --git a/ios/web_view/internal/sync/web_view_sync_client.mm b/ios/web_view/internal/sync/web_view_sync_client.mm
index df2a894..e2f2d6f 100644
--- a/ios/web_view/internal/sync/web_view_sync_client.mm
+++ b/ios/web_view/internal/sync/web_view_sync_client.mm
@@ -101,7 +101,10 @@
           /*account_bookmark_sync_service=*/nullptr,
           /*power_bookmark_service=*/nullptr,
           /*supervised_user_settings_service=*/nullptr,
-          /*plus_address_webdata_service=*/nullptr);
+          /*plus_address_webdata_service=*/nullptr,
+          /*TODO(crbug.com/330201909) implement on iOS
+             product_specifications_service= */
+          nullptr);
   // TODO(crbug.com/1434661): introduce ios webview version of
   // TrustedVaultServiceFactory.
   trusted_vault_client_ = std::make_unique<WebViewTrustedVaultClient>();