chromium/ios/chrome/browser/sync/model/device_info_sync_service_factory.mm

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/sync/model/device_info_sync_service_factory.h"

#import <optional>
#import <utility>

#import "base/functional/bind.h"
#import "base/memory/raw_ptr.h"
#import "base/memory/singleton.h"
#import "base/strings/sys_string_conversions.h"
#import "base/time/default_clock.h"
#import "components/keyed_service/core/service_access_type.h"
#import "components/keyed_service/ios/browser_state_dependency_manager.h"
#import "components/send_tab_to_self/features.h"
#import "components/signin/public/base/device_id_helper.h"
#import "components/signin/public/identity_manager/identity_manager.h"
#import "components/sync/invalidations/sync_invalidations_service.h"
#import "components/sync/model/data_type_store_service.h"
#import "components/sync/protocol/sync_enums.pb.h"
#import "components/sync_device_info/device_info_prefs.h"
#import "components/sync_device_info/device_info_sync_client.h"
#import "components/sync_device_info/device_info_sync_service_impl.h"
#import "components/sync_device_info/local_device_info_provider_impl.h"
#import "ios/chrome/browser/push_notification/model/push_notification_service.h"
#import "ios/chrome/browser/shared/model/application_context/application_context.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
#import "ios/chrome/browser/shared/model/profile/profile_manager_ios.h"
#import "ios/chrome/browser/signin/model/identity_manager_factory.h"
#import "ios/chrome/browser/sync/model/data_type_store_service_factory.h"
#import "ios/chrome/browser/sync/model/sync_invalidations_service_factory.h"
#import "ios/chrome/common/channel_info.h"

namespace {

class DeviceInfoSyncClient : public syncer::DeviceInfoSyncClient {
 public:
  DeviceInfoSyncClient(
      PrefService* prefs,
      syncer::SyncInvalidationsService* sync_invalidations_service,
      signin::IdentityManager* identity_manager)
      : prefs_(prefs),
        sync_invalidations_service_(sync_invalidations_service),
        identity_manager_(identity_manager) {}
  ~DeviceInfoSyncClient() override = default;

  // syncer::DeviceInfoSyncClient:
  std::string GetSigninScopedDeviceId() const override {
    return signin::GetSigninScopedDeviceId(prefs_);
  }

  // syncer::DeviceInfoSyncClient:
  bool GetSendTabToSelfReceivingEnabled() const override {
    // Always true starting with M101, see crbug.com/1299833. Older clients and
    // clients from other embedders might still return false.
    return true;
  }

  // syncer::DeviceInfoSyncClient:
  sync_pb::SyncEnums_SendTabReceivingType GetSendTabToSelfReceivingType()
      const override {
    // TODO(crbug.com/343495515): Check if push notifications are enabled on
    // device.
    return base::FeatureList::IsEnabled(
               send_tab_to_self::kSendTabToSelfIOSPushNotifications)
               ? sync_pb::
                     SyncEnums_SendTabReceivingType_SEND_TAB_RECEIVING_TYPE_CHROME_AND_PUSH_NOTIFICATION
               : sync_pb::
                     SyncEnums_SendTabReceivingType_SEND_TAB_RECEIVING_TYPE_CHROME_OR_UNSPECIFIED;
  }

  // syncer::DeviceInfoSyncClient:
  std::optional<syncer::DeviceInfo::SharingInfo> GetLocalSharingInfo()
      const override {
    if (!identity_manager_ ||
        !base::FeatureList::IsEnabled(
            send_tab_to_self::kSendTabToSelfIOSPushNotifications)) {
      return std::nullopt;
    }
    std::string gaia_id =
        identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin)
            .gaia;
    std::string representative_target_id =
        GetApplicationContext()
            ->GetPushNotificationService()
            ->GetRepresentativeTargetIdForGaiaId(
                base::SysUTF8ToNSString(gaia_id));
    // Sharing info is not implemented on iOS, so empty structs are passed in.
    // TODO(crbug.com/352370268): Use SharingSyncPreference to hold SharingInfo.
    return syncer::DeviceInfo::SharingInfo(
        syncer::DeviceInfo::SharingTargetInfo(),
        syncer::DeviceInfo::SharingTargetInfo(), representative_target_id,
        std::set<sync_pb::SharingSpecificFields_EnabledFeatures>());
  }

  // syncer::DeviceInfoSyncClient:
  syncer::DeviceInfo::PhoneAsASecurityKeyInfo::StatusOrInfo
  GetPhoneAsASecurityKeyInfo() const override {
    return syncer::DeviceInfo::PhoneAsASecurityKeyInfo::NoSupport();
  }

  // syncer::DeviceInfoSyncClient:
  std::optional<std::string> GetFCMRegistrationToken() const override {
    if (sync_invalidations_service_) {
      return sync_invalidations_service_->GetFCMRegistrationToken();
    }
    // If the service is not enabled, then the registration token must be empty,
    // not unknown (std::nullopt). This is needed to reset previous token if
    // the invalidations have been turned off.
    return std::string();
  }

  // syncer::DeviceInfoSyncClient:
  std::optional<syncer::DataTypeSet> GetInterestedDataTypes() const override {
    if (sync_invalidations_service_) {
      return sync_invalidations_service_->GetInterestedDataTypes();
    }
    // If the service is not enabled, then the list of types must be empty, not
    // unknown (std::nullopt). This is needed to reset previous types if the
    // invalidations have been turned off.
    return syncer::DataTypeSet();
  }

  // syncer::DeviceInfoSyncClient:
  // Returns false since we only care about Chrome OS devices
  bool IsUmaEnabledOnCrOSDevice() const override { return false; }

 private:
  const raw_ptr<PrefService> prefs_;
  const raw_ptr<syncer::SyncInvalidationsService> sync_invalidations_service_;
  const raw_ptr<signin::IdentityManager> identity_manager_;
};

}  // namespace

// static
syncer::DeviceInfoSyncService* DeviceInfoSyncServiceFactory::GetForBrowserState(
    ChromeBrowserState* browser_state) {
  return static_cast<syncer::DeviceInfoSyncService*>(
      GetInstance()->GetServiceForBrowserState(browser_state, true));
}

// static
DeviceInfoSyncServiceFactory* DeviceInfoSyncServiceFactory::GetInstance() {
  return base::Singleton<DeviceInfoSyncServiceFactory>::get();
}

// static
void DeviceInfoSyncServiceFactory::GetAllDeviceInfoTrackers(
    std::vector<const syncer::DeviceInfoTracker*>* trackers) {
  DCHECK(trackers);
  for (ChromeBrowserState* browser_state :
       GetApplicationContext()->GetProfileManager()->GetLoadedProfiles()) {
    syncer::DeviceInfoSyncService* service =
        DeviceInfoSyncServiceFactory::GetForBrowserState(browser_state);
    if (service != nullptr) {
      const syncer::DeviceInfoTracker* tracker =
          service->GetDeviceInfoTracker();
      if (tracker != nullptr) {
        trackers->push_back(tracker);
      }
    }
  }
}

DeviceInfoSyncServiceFactory::DeviceInfoSyncServiceFactory()
    : BrowserStateKeyedServiceFactory(
          "DeviceInfoSyncService",
          BrowserStateDependencyManager::GetInstance()) {
  DependsOn(DataTypeStoreServiceFactory::GetInstance());
  DependsOn(SyncInvalidationsServiceFactory::GetInstance());
  DependsOn(IdentityManagerFactory::GetInstance());
}

DeviceInfoSyncServiceFactory::~DeviceInfoSyncServiceFactory() {}

std::unique_ptr<KeyedService>
DeviceInfoSyncServiceFactory::BuildServiceInstanceFor(
    web::BrowserState* context) const {
  ChromeBrowserState* browser_state =
      ChromeBrowserState::FromBrowserState(context);

  syncer::SyncInvalidationsService* const sync_invalidations_service =
      SyncInvalidationsServiceFactory::GetForBrowserState(browser_state);
  signin::IdentityManager* const identity_manager =
      IdentityManagerFactory::GetForBrowserState(browser_state);
  auto device_info_sync_client = std::make_unique<DeviceInfoSyncClient>(
      browser_state->GetPrefs(), sync_invalidations_service, identity_manager);
  auto local_device_info_provider =
      std::make_unique<syncer::LocalDeviceInfoProviderImpl>(
          ::GetChannel(), ::GetVersionString(), device_info_sync_client.get());
  auto device_prefs = std::make_unique<syncer::DeviceInfoPrefs>(
      browser_state->GetPrefs(), base::DefaultClock::GetInstance());

  return std::make_unique<syncer::DeviceInfoSyncServiceImpl>(
      DataTypeStoreServiceFactory::GetForBrowserState(browser_state)
          ->GetStoreFactory(),
      std::move(local_device_info_provider), std::move(device_prefs),
      std::move(device_info_sync_client), sync_invalidations_service);
}