| // Copyright 2026 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/sync/cross_device_theme_tracker_factory.h" |
| |
| #include "base/feature_list.h" |
| #include "base/functional/bind.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/profiles/profile_selections.h" |
| #include "chrome/browser/sync/data_type_store_service_factory.h" |
| #include "chrome/browser/sync/device_info_sync_service_factory.h" |
| #include "chrome/common/channel_info.h" |
| #include "components/sync/base/report_unrecoverable_error.h" |
| #include "components/sync/model/client_tag_based_data_type_processor.h" |
| #include "components/sync/model/data_type_store_service.h" |
| #include "components/sync_device_info/device_info_sync_service.h" |
| #include "components/themes/cross_device/cross_device_theme_sync_bridge.h" |
| #include "components/themes/cross_device/features.h" |
| #include "components/themes/cross_device/theme_translation.h" |
| |
| #if BUILDFLAG(IS_ANDROID) |
| #include "chrome/browser/sync/cross_device_theme_tracker_android.h" |
| #endif |
| |
| namespace { |
| |
| template <typename RemoteSpecifics, typename LocalSpecifics> |
| void RegisterBridgeHelper( |
| syncer::DataType type, |
| base::RepeatingCallback<themes::DeviceThemeInfo<LocalSpecifics>( |
| const RemoteSpecifics&)> translate_cb, |
| themes::CrossDeviceThemeTracker<LocalSpecifics>* tracker, |
| syncer::DataTypeStoreService* store_service, |
| version_info::Channel channel) { |
| syncer::RepeatingDataTypeStoreFactory store_factory = |
| store_service->GetStoreFactory(); |
| auto processor = std::make_unique<syncer::ClientTagBasedDataTypeProcessor>( |
| type, base::BindRepeating(&syncer::ReportUnrecoverableError, channel)); |
| |
| auto bridge = std::make_unique< |
| themes::CrossDeviceThemeSyncBridge<RemoteSpecifics, LocalSpecifics>>( |
| type, std::move(translate_cb), |
| base::BindRepeating( |
| &themes::CrossDeviceThemeTracker<LocalSpecifics>::UpdateThemeInfo, |
| base::Unretained(tracker)), |
| base::BindRepeating( |
| &themes::CrossDeviceThemeTracker<LocalSpecifics>::RemoveThemeInfo, |
| base::Unretained(tracker)), |
| base::BindRepeating( |
| &themes::CrossDeviceThemeTracker<LocalSpecifics>::OnBridgeSyncStarted, |
| base::Unretained(tracker), type), |
| base::BindRepeating(&themes::CrossDeviceThemeTracker< |
| LocalSpecifics>::OnBridgeSyncDisabled, |
| base::Unretained(tracker), type), |
| std::move(processor), store_factory); |
| |
| tracker->RegisterBridge(type, std::move(bridge)); |
| } |
| |
| } // namespace |
| |
| // static |
| themes::CrossDeviceThemeTracker< |
| CrossDeviceThemeTrackerFactory::LocalThemeSpecifics>* |
| CrossDeviceThemeTrackerFactory::GetForProfile(Profile* profile) { |
| return static_cast<themes::CrossDeviceThemeTracker<LocalThemeSpecifics>*>( |
| GetInstance()->GetServiceForBrowserContext(profile, true)); |
| } |
| |
| // static |
| CrossDeviceThemeTrackerFactory* CrossDeviceThemeTrackerFactory::GetInstance() { |
| static base::NoDestructor<CrossDeviceThemeTrackerFactory> instance; |
| return instance.get(); |
| } |
| |
| CrossDeviceThemeTrackerFactory::CrossDeviceThemeTrackerFactory() |
| : ProfileKeyedServiceFactory( |
| "CrossDeviceThemeTracker", |
| ProfileSelections::Builder() |
| .WithRegular(ProfileSelection::kOriginalOnly) |
| .WithGuest(ProfileSelection::kOriginalOnly) |
| .Build()) { |
| DependsOn(DeviceInfoSyncServiceFactory::GetInstance()); |
| DependsOn(DataTypeStoreServiceFactory::GetInstance()); |
| } |
| |
| CrossDeviceThemeTrackerFactory::~CrossDeviceThemeTrackerFactory() = default; |
| |
| std::unique_ptr<KeyedService> |
| CrossDeviceThemeTrackerFactory::BuildServiceInstanceForBrowserContext( |
| content::BrowserContext* context) const { |
| if (!base::FeatureList::IsEnabled(themes::kCrossDeviceThemeTracker)) { |
| return nullptr; |
| } |
| |
| Profile* profile = Profile::FromBrowserContext(context); |
| |
| syncer::DeviceInfoSyncService* device_info_sync_service = |
| DeviceInfoSyncServiceFactory::GetForProfile(profile); |
| syncer::DeviceInfoTracker* device_info_tracker = |
| device_info_sync_service |
| ? device_info_sync_service->GetDeviceInfoTracker() |
| : nullptr; |
| |
| syncer::DataTypeStoreService* store_service = |
| DataTypeStoreServiceFactory::GetForProfile(profile); |
| version_info::Channel channel = chrome::GetChannel(); |
| |
| #if BUILDFLAG(IS_ANDROID) |
| auto tracker = std::make_unique<themes::CrossDeviceThemeTrackerAndroid>( |
| device_info_tracker); |
| #else |
| auto tracker = |
| std::make_unique<themes::CrossDeviceThemeTracker<LocalThemeSpecifics>>( |
| device_info_tracker); |
| #endif |
| |
| #if BUILDFLAG(IS_ANDROID) |
| // Construct Desktop bridge. |
| RegisterBridgeHelper<sync_pb::ThemeSpecifics, LocalThemeSpecifics>( |
| syncer::THEMES, base::BindRepeating(&themes::TranslateDesktop), |
| tracker.get(), store_service, channel); |
| #else |
| // Construct Android bridge. |
| RegisterBridgeHelper<sync_pb::ThemeAndroidSpecifics, LocalThemeSpecifics>( |
| syncer::THEMES_ANDROID, base::BindRepeating(&themes::TranslateAndroid), |
| tracker.get(), store_service, channel); |
| #endif |
| |
| // Construct iOS bridge. |
| RegisterBridgeHelper<sync_pb::ThemeIosSpecifics, LocalThemeSpecifics>( |
| syncer::THEMES_IOS, base::BindRepeating(&themes::TranslateIos), |
| tracker.get(), store_service, channel); |
| |
| return tracker; |
| } |