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

#include "components/sync/service/sync_prefs.h"

#include <utility>

#include "base/auto_reset.h"
#include "base/base64.h"
#include "base/check_op.h"
#include "base/containers/to_vector.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/notreached.h"
#include "base/observer_list.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/pref_value_map.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/saved_tab_groups/public/pref_names.h"
#include "components/signin/public/base/gaia_id_hash.h"
#include "components/signin/public/base/signin_buildflags.h"
#include "components/signin/public/base/signin_pref_names.h"
#include "components/signin/public/base/signin_prefs.h"
#include "components/signin/public/base/signin_switches.h"
#include "components/sync/base/account_pref_utils.h"
#include "components/sync/base/custom_passphrase_bootstrap_token.h"
#include "components/sync/base/features.h"
#include "components/sync/base/passphrase_enums.h"
#include "components/sync/base/pref_names.h"
#include "components/sync/base/user_selectable_type.h"
#include "components/sync/protocol/nigori_specifics.pb.h"
#include "components/sync/service/glue/sync_transport_data_prefs.h"
#include "components/sync/service/sync_feature_status_for_migrations_recorder.h"
#include "google_apis/gaia/gaia_id.h"

namespace syncer {

namespace {

// State of the migration done by MaybeMigrateCustomPassphrasePref().
constexpr char kSyncEncryptionBootstrapTokenPerAccountMigrationDone[] =
    "sync.encryption_bootstrap_token_per_account_migration_done";

#if BUILDFLAG(ENABLE_DICE_SUPPORT)
// Pref to record if the one-off MaybeMigrateAutofillToPerAccountPref()
// migration ran.
constexpr char kAutofillPerAccountPrefMigrationDone[] =
    "sync.passwords_per_account_pref_migration_done";
#endif  //  BUILDFLAG(ENABLE_DICE_SUPPORT)

constexpr int kNotMigrated = 0;
constexpr int kMigratedPart1ButNot2 = 1;
constexpr int kMigratedPart2AndFullyDone = 2;

// Encodes a protobuf instance of type
// sync_pb::TrustedVaultAutoUpgradeExperimentGroup in a way that can be safely
// stored in prefs, i.e. using base64 encoding.
std::string EncodeTrustedVaultAutoUpgradeExperimentGroupToString(
    const sync_pb::TrustedVaultAutoUpgradeExperimentGroup& group) {
  return base::Base64Encode(group.SerializeAsString());
}

// Does the opposite of EncodeTrustedVaultAutoUpgradeExperimentGroupToString(),
// i.e. transforms from a string representation to a protobuf instance.
sync_pb::TrustedVaultAutoUpgradeExperimentGroup
DecodeTrustedVaultAutoUpgradeExperimentGroupFromString(
    const std::string& encoded_group) {
  sync_pb::TrustedVaultAutoUpgradeExperimentGroup proto;
  std::string serialized_proto;
  if (!base::Base64Decode(encoded_group, &serialized_proto)) {
    return proto;
  }
  proto.ParseFromString(serialized_proto);
  return proto;
}

bool IsBookmarksSelectedByDefaultInTransportMode(PrefService& pref_service,
                                                 const GaiaId& gaia_id) {
#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
  return IsReplaceSyncPromosWithSignInPromosEnabled();
#else
  // If `kReplaceSyncPromosWithSignInPromos` is enabled, bookmarks and reading
  // list are enabled by default for new sign-ins (not pre-existing sessions).
  // This pref is set if the above conditions are met.
  // Note: If `kReplaceSyncPromosWithSignInPromos` gets disabled, the pref is
  // not reset and users will keep their bookmarks because that reduces the
  // risks of perceived dataloss.
  return SigninPrefs(pref_service).GetBookmarksExplicitBrowserSignin(gaia_id);
#endif  // BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
}

bool IsExtensionsSelectedByDefaultInTransportMode(PrefService& pref_service,
                                                  const GaiaId& gaia_id) {
#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
  return IsReplaceSyncPromosWithSignInPromosEnabled();
#else
  // if `kReplaceSyncPromosWithSignInPromos` is enabled, extensions are enabled
  // by default for new sign-ins (not pre-existing sessions). This pref is set
  // if the above conditions are met.
  // Note: If `kReplaceSyncPromosWithSignInPromos` gets disabled, the pref is
  // not reset and users will keep their extensions because that reduces the
  // risks of perceived dataloss.
  return SigninPrefs(pref_service).GetExtensionsExplicitBrowserSignin(gaia_id);
#endif  // BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
}

}  // namespace

SyncPrefObserver::~SyncPrefObserver() = default;

SyncPrefs::SyncPrefs(PrefService* pref_service)
    : pref_service_(pref_service),
      local_sync_enabled_(
          pref_service_->GetBoolean(prefs::kEnableLocalSyncBackend)) {
  DCHECK(pref_service);
  // Watch the preference that indicates sync is managed so we can take
  // appropriate action.
  pref_sync_managed_.Init(
      prefs::internal::kSyncManaged, pref_service_,
      base::BindRepeating(&SyncPrefs::OnSyncManagedPrefChanged,
                          base::Unretained(this)));

  // Observe changes to all of the prefs that may influence the selected types.
  pref_change_registrar_.Init(pref_service_);
  // The individual data type prefs are used for syncing users, as well as for
  // enterprise policy.
  for (UserSelectableType type : UserSelectableTypeSet::All()) {
    pref_change_registrar_.Add(
        GetPrefNameForType(type),
        base::BindRepeating(&SyncPrefs::OnSelectedTypesPrefChanged,
                            base::Unretained(this)));
  }
  // The "sync everything" pref is used for syncing users.
  pref_change_registrar_.Add(
      prefs::internal::kSyncKeepEverythingSynced,
      base::BindRepeating(&SyncPrefs::OnSelectedTypesPrefChanged,
                          base::Unretained(this)));
  // The per-account data types dictionary pref is used for signed-in
  // non-syncing users.
  pref_change_registrar_.Add(
      prefs::internal::kSelectedTypesPerAccount,
      base::BindRepeating(&SyncPrefs::OnSelectedTypesPrefChanged,
                          base::Unretained(this)));

#if BUILDFLAG(ENABLE_DICE_SUPPORT)
  // The explicit browser signin pref is used for determining whether some data
  // types are selected by default. Therefore, upon a change, the selected types
  //  may change.
  pref_change_registrar_.Add(
      ::prefs::kExplicitBrowserSignin,
      base::BindRepeating(&SyncPrefs::OnSelectedTypesPrefChanged,
                          base::Unretained(this)));
#endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
}

SyncPrefs::~SyncPrefs() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}

// static
void SyncPrefs::RegisterProfilePrefs(PrefRegistrySimple* registry) {
  // Actual user-controlled preferences.
  registry->RegisterBooleanPref(prefs::internal::kSyncKeepEverythingSynced,
                                true);
  registry->RegisterDictionaryPref(prefs::internal::kSelectedTypesPerAccount);
  for (UserSelectableType type : UserSelectableTypeSet::All()) {
    RegisterTypeSelectedPref(registry, type);
  }
#if BUILDFLAG(IS_CHROMEOS)
  registry->RegisterBooleanPref(prefs::internal::kSyncDisabledViaDashboard,
                                false);
  registry->RegisterBooleanPref(prefs::internal::kSyncAllOsTypes, true);
  registry->RegisterBooleanPref(prefs::internal::kSyncOsApps, false);
  registry->RegisterBooleanPref(prefs::internal::kSyncOsPreferences, false);
  registry->RegisterBooleanPref(prefs::internal::kSyncWifiConfigurations,
                                false);
#else   // BUILDFLAG(IS_CHROMEOS)
  registry->RegisterBooleanPref(
      prefs::internal::kSyncInitialSyncFeatureSetupComplete, false);
#endif  // BUILDFLAG(IS_CHROMEOS)

  registry->RegisterIntegerPref(prefs::internal::kSyncToSigninMigrationState,
                                kNotMigrated);
  registry->RegisterBooleanPref(
      prefs::internal::kMigrateReadingListFromLocalToAccount, false);
  registry->RegisterBooleanPref(
      prefs::internal::kMigrateExtensionsFromLocalToAccount, false);
  registry->RegisterBooleanPref(
      prefs::internal::kMigrateThemeFromLocalToAccount, false);
  registry->RegisterBooleanPref(
      prefs::kCleanUpStatsTableFromAccountPasswordStore, false);

  // The passphrase type, determined upon the first engine initialization.
  registry->RegisterIntegerPref(
      prefs::internal::kSyncCachedPassphraseType,
      sync_pb::NigoriSpecifics_PassphraseType_UNKNOWN);
  // The user's TrustedVaultAutoUpgradeExperimentGroup, determined the first
  // time the engine is successfully initialized.
  registry->RegisterStringPref(
      prefs::internal::kSyncCachedTrustedVaultAutoUpgradeExperimentGroup, "");
  // The encryption bootstrap token represents a user-entered passphrase.
  registry->RegisterStringPref(prefs::internal::kSyncEncryptionBootstrapToken,
                               std::string());

  // Cached notion of whether or not a persistent auth error exists.
  registry->RegisterBooleanPref(
      prefs::internal::kSyncCachedPersistentAuthErrorForMetrics, false);

  // The encryption bootstrap token represents a user-entered passphrase per
  // account.
  registry->RegisterDictionaryPref(
      prefs::internal::kSyncEncryptionBootstrapTokenPerAccount);
  // For migration only, tracks if the EncryptionBootstrapToken is migrated.
  registry->RegisterBooleanPref(
      kSyncEncryptionBootstrapTokenPerAccountMigrationDone, false);

  registry->RegisterBooleanPref(prefs::internal::kSyncManaged, false);
  registry->RegisterIntegerPref(
      prefs::internal::kSyncPassphrasePromptMutedProductVersion, 0);
  registry->RegisterBooleanPref(prefs::kEnableLocalSyncBackend, false);
  registry->RegisterFilePathPref(prefs::kLocalSyncBackendDir, base::FilePath());
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
  registry->RegisterBooleanPref(kAutofillPerAccountPrefMigrationDone, false);
#endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
  registry->RegisterTimePref(
      prefs::internal::kFirstTimeTriedToMigrateSyncFeaturePausedToSignin,
      base::Time());

  SyncFeatureStatusForMigrationsRecorder::RegisterProfilePrefs(registry);
}

void SyncPrefs::AddObserver(SyncPrefObserver* sync_pref_observer) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  sync_pref_observers_.AddObserver(sync_pref_observer);
}

void SyncPrefs::RemoveObserver(SyncPrefObserver* sync_pref_observer) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  sync_pref_observers_.RemoveObserver(sync_pref_observer);
}

bool SyncPrefs::IsInitialSyncFeatureSetupComplete() const {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
#if BUILDFLAG(IS_CHROMEOS)
  return true;
#else   // BUILDFLAG(IS_CHROMEOS)
  return pref_service_->GetBoolean(
      prefs::internal::kSyncInitialSyncFeatureSetupComplete);
#endif  // BUILDFLAG(IS_CHROMEOS)
}

#if !BUILDFLAG(IS_CHROMEOS)
void SyncPrefs::SetInitialSyncFeatureSetupComplete() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  pref_service_->SetBoolean(
      prefs::internal::kSyncInitialSyncFeatureSetupComplete, true);
}

void SyncPrefs::ClearInitialSyncFeatureSetupComplete() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  pref_service_->ClearPref(
      prefs::internal::kSyncInitialSyncFeatureSetupComplete);
}
#endif  // !BUILDFLAG(IS_CHROMEOS)

bool SyncPrefs::HasKeepEverythingSynced() const {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  return pref_service_->GetBoolean(prefs::internal::kSyncKeepEverythingSynced);
}

UserSelectableTypeSet SyncPrefs::GetSelectedTypesForAccount(
    const GaiaId& gaia_id) const {
  const signin::GaiaIdHash gaia_id_hash =
      signin::GaiaIdHash::FromGaiaId(gaia_id);
  UserSelectableTypeSet selected_types;

  for (UserSelectableType type : UserSelectableTypeSet::All()) {
    if (!IsTypeSupportedInTransportMode(type)) {
      continue;
    }
    const char* pref_name = GetPrefNameForType(type);
    DCHECK(pref_name);
    bool type_enabled = false;
    if (IsTypeManagedByPolicy(type) || IsTypeManagedByCustodian(type)) {
      type_enabled = pref_service_->GetBoolean(pref_name);
    } else {
      const base::Value* pref_value = GetAccountKeyedPrefDictEntry(
          pref_service_, prefs::internal::kSelectedTypesPerAccount,
          gaia_id_hash, pref_name);
      if (pref_value && pref_value->is_bool()) {
        type_enabled = pref_value->GetBool();
      } else {
        type_enabled = IsTypeSelectedByDefaultInTransportMode(type, gaia_id);
      }
    }
    if (type_enabled) {
      selected_types.Put(type);
    }
  }

  return selected_types;
}

UserSelectableTypeSet SyncPrefs::GetSelectedTypesForSyncingUser() const {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  UserSelectableTypeSet selected_types;

  for (UserSelectableType type : UserSelectableTypeSet::All()) {
    const char* pref_name = GetPrefNameForType(type);
    DCHECK(pref_name);
    if (pref_service_->GetBoolean(pref_name) ||
        (!IsTypeManagedByPolicy(type) && !IsTypeManagedByCustodian(type) &&
         pref_service_->GetBoolean(
             prefs::internal::kSyncKeepEverythingSynced))) {
      // In full-sync mode, the "sync everything" bit is honored. If it's
      // true, all types are considered selected, irrespective of their
      // individual prefs.
      selected_types.Put(type);
    }
  }

  return selected_types;
}

bool SyncPrefs::IsTypeManagedByPolicy(UserSelectableType type) const {
  const char* pref_name = GetPrefNameForType(type);
  CHECK(pref_name);
  return pref_service_->IsManagedPreference(pref_name);
}

bool SyncPrefs::IsTypeManagedByCustodian(UserSelectableType type) const {
  const char* pref_name = GetPrefNameForType(type);
  CHECK(pref_name);
  return pref_service_->IsPreferenceManagedByCustodian(pref_name);
}

bool SyncPrefs::DoesTypeHaveDefaultValueForAccount(
    const UserSelectableType type,
    const GaiaId& gaia_id) {
  const char* pref_name = GetPrefNameForType(type);
  DCHECK(pref_name);

  const base::Value* value = GetAccountKeyedPrefDictEntry(
      pref_service_, prefs::internal::kSelectedTypesPerAccount,
      signin::GaiaIdHash::FromGaiaId(gaia_id), pref_name);

  return !value;
}

bool SyncPrefs::IsTypeDisabledByUserForAccount(const UserSelectableType type,
                                               const GaiaId& gaia_id) {
  const char* pref_name = GetPrefNameForType(type);
  DCHECK(pref_name);

  const base::Value* value = GetAccountKeyedPrefDictEntry(
      pref_service_, prefs::internal::kSelectedTypesPerAccount,
      signin::GaiaIdHash::FromGaiaId(gaia_id), pref_name);

  if (value && value->is_bool()) {
    return !value->GetBool();
  }
  return false;
}

void SyncPrefs::SetSelectedTypesForSyncingUser(
    bool keep_everything_synced,
    UserSelectableTypeSet registered_types,
    UserSelectableTypeSet selected_types) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  {
    // Prevent OnSelectedTypesPrefChanged() from notifying observers about each
    // of the type changes individually.
    base::AutoReset<bool> batch_update(&batch_updating_selected_types_, true);

    pref_service_->SetBoolean(prefs::internal::kSyncKeepEverythingSynced,
                              keep_everything_synced);

    for (UserSelectableType type : registered_types) {
      const char* pref_name = GetPrefNameForType(type);
      pref_service_->SetBoolean(pref_name, selected_types.Has(type));
    }
  }

  for (SyncPrefObserver& observer : sync_pref_observers_) {
    observer.OnSelectedTypesPrefChange();
  }
}

void SyncPrefs::SetSelectedTypeForAccount(UserSelectableType type,
                                          bool is_type_on,
                                          const GaiaId& gaia_id) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  CHECK(!gaia_id.empty());

  SetAccountKeyedPrefDictEntry(
      pref_service_, prefs::internal::kSelectedTypesPerAccount,
      signin::GaiaIdHash::FromGaiaId(gaia_id), GetPrefNameForType(type),
      base::Value(is_type_on));
}

void SyncPrefs::ResetSelectedTypeForAccount(UserSelectableType type,
                                            const GaiaId& gaia_id) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  RemoveAccountKeyedPrefDictEntry(
      pref_service_, prefs::internal::kSelectedTypesPerAccount,
      signin::GaiaIdHash::FromGaiaId(gaia_id), GetPrefNameForType(type));
}

void SyncPrefs::KeepAccountSettingsPrefsOnlyForUsers(
    const std::vector<GaiaId>& available_gaia_ids) {
  std::vector<signin::GaiaIdHash> hashes =
      base::ToVector(available_gaia_ids, &signin::GaiaIdHash::FromGaiaId);

  KeepAccountKeyedPrefValuesOnlyForUsers(
      pref_service_, prefs::internal::kSelectedTypesPerAccount, hashes);
  KeepAccountKeyedPrefValuesOnlyForUsers(
      pref_service_, prefs::internal::kSyncEncryptionBootstrapTokenPerAccount,
      hashes);

  // TODO(crbug.com/368409110): This is not the right place for clearing
  // transport-data-related prefs - ideally there'd be an observer API for
  // "accounts on this device".
  SyncTransportDataPrefs::KeepAccountSettingsPrefsOnlyForUsers(pref_service_,
                                                               hashes);

  // TODO(crbug.com/368409110): This is *absolutely* not the right place for
  // clearing not-sync-related prefs. Move this elsewhere once signin code
  // provides an observer API for "accounts on this device".
  tab_groups::prefs::KeepAccountSettingsPrefsOnlyForUsers(pref_service_,
                                                          hashes);
}

#if BUILDFLAG(IS_CHROMEOS)
bool SyncPrefs::IsSyncFeatureDisabledViaDashboard() const {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  return pref_service_->GetBoolean(prefs::internal::kSyncDisabledViaDashboard);
}

void SyncPrefs::SetSyncFeatureDisabledViaDashboard() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  pref_service_->SetBoolean(prefs::internal::kSyncDisabledViaDashboard, true);
}

void SyncPrefs::ClearSyncFeatureDisabledViaDashboard() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  pref_service_->ClearPref(prefs::internal::kSyncDisabledViaDashboard);
}

bool SyncPrefs::IsSyncAllOsTypesEnabled() const {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  return pref_service_->GetBoolean(prefs::internal::kSyncAllOsTypes);
}

UserSelectableOsTypeSet SyncPrefs::GetSelectedOsTypes() const {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  UserSelectableOsTypeSet selected_types;
  const bool sync_all_os_types = IsSyncAllOsTypesEnabled();
  for (UserSelectableOsType type : UserSelectableOsTypeSet::All()) {
    const char* pref_name = GetPrefNameForOsType(type);
    DCHECK(pref_name);
    // If the type is managed, `sync_all_os_types` is ignored for this type.
    if (pref_service_->GetBoolean(pref_name) ||
        (sync_all_os_types && !IsOsTypeManagedByPolicy(type))) {
      selected_types.Put(type);
    }
  }
  return selected_types;
}

bool SyncPrefs::IsOsTypeManagedByPolicy(UserSelectableOsType type) const {
  const char* pref_name = GetPrefNameForOsType(type);
  CHECK(pref_name);
  return pref_service_->IsManagedPreference(pref_name);
}

void SyncPrefs::SetSelectedOsTypes(bool sync_all_os_types,
                                   UserSelectableOsTypeSet registered_types,
                                   UserSelectableOsTypeSet selected_types) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  {
    // Prevent OnSelectedTypesPrefChanged() from notifying about each of the
    // type changes individually.
    base::AutoReset<bool> batch_update(&batch_updating_selected_types_, true);

    pref_service_->SetBoolean(prefs::internal::kSyncAllOsTypes,
                              sync_all_os_types);
    for (UserSelectableOsType type : registered_types) {
      const char* pref_name = GetPrefNameForOsType(type);
      DCHECK(pref_name);
      pref_service_->SetBoolean(pref_name, selected_types.Has(type));
    }
  }
  for (SyncPrefObserver& observer : sync_pref_observers_) {
    observer.OnSelectedTypesPrefChange();
  }
}

// static
const char* SyncPrefs::GetPrefNameForOsTypeForTesting(
    UserSelectableOsType type) {
  return GetPrefNameForOsType(type);
}

// static
const char* SyncPrefs::GetPrefNameForOsType(UserSelectableOsType type) {
  switch (type) {
    case UserSelectableOsType::kOsApps:
      return prefs::internal::kSyncOsApps;
    case UserSelectableOsType::kOsPreferences:
      return prefs::internal::kSyncOsPreferences;
    case UserSelectableOsType::kOsWifiConfigurations:
      return prefs::internal::kSyncWifiConfigurations;
  }
  NOTREACHED();
}

// static
void SyncPrefs::SetOsTypeDisabledByPolicy(PrefValueMap* policy_prefs,
                                          UserSelectableOsType type) {
  const char* pref_name = syncer::SyncPrefs::GetPrefNameForOsType(type);
  CHECK(pref_name);
  policy_prefs->SetValue(pref_name, base::Value(false));
}
#endif  // BUILDFLAG(IS_CHROMEOS)

bool SyncPrefs::IsSyncClientDisabledByPolicy() const {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  return pref_service_->GetBoolean(prefs::internal::kSyncManaged);
}

std::optional<PassphraseType> SyncPrefs::GetCachedPassphraseType() const {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  return ProtoPassphraseInt32ToEnum(
      pref_service_->GetInteger(prefs::internal::kSyncCachedPassphraseType));
}

void SyncPrefs::SetCachedPassphraseType(PassphraseType passphrase_type) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  pref_service_->SetInteger(prefs::internal::kSyncCachedPassphraseType,
                            EnumPassphraseTypeToProto(passphrase_type));
}

void SyncPrefs::ClearCachedPassphraseType() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  pref_service_->ClearPref(prefs::internal::kSyncCachedPassphraseType);
}

bool SyncPrefs::HasCachedPersistentAuthErrorForMetrics() const {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  return pref_service_->GetBoolean(
      prefs::internal::kSyncCachedPersistentAuthErrorForMetrics);
}

void SyncPrefs::SetHasCachedPersistentAuthErrorForMetrics(
    bool has_persistent_auth_error) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  pref_service_->SetBoolean(
      prefs::internal::kSyncCachedPersistentAuthErrorForMetrics,
      has_persistent_auth_error);
}

void SyncPrefs::ClearCachedPersistentAuthErrorForMetrics() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  pref_service_->ClearPref(
      prefs::internal::kSyncCachedPersistentAuthErrorForMetrics);
}

std::optional<sync_pb::TrustedVaultAutoUpgradeExperimentGroup>
SyncPrefs::GetCachedTrustedVaultAutoUpgradeExperimentGroup() const {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  const std::string& encoded_group = pref_service_->GetString(
      prefs::internal::kSyncCachedTrustedVaultAutoUpgradeExperimentGroup);
  if (encoded_group.empty()) {
    return std::nullopt;
  }
  return DecodeTrustedVaultAutoUpgradeExperimentGroupFromString(encoded_group);
}

void SyncPrefs::SetCachedTrustedVaultAutoUpgradeExperimentGroup(
    const sync_pb::TrustedVaultAutoUpgradeExperimentGroup& group) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  pref_service_->SetString(
      prefs::internal::kSyncCachedTrustedVaultAutoUpgradeExperimentGroup,
      EncodeTrustedVaultAutoUpgradeExperimentGroupToString(group));
}

void SyncPrefs::ClearCachedTrustedVaultAutoUpgradeExperimentGroup() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  pref_service_->ClearPref(
      prefs::internal::kSyncCachedTrustedVaultAutoUpgradeExperimentGroup);
}

void SyncPrefs::ClearAllEncryptionBootstrapTokens() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  pref_service_->ClearPref(prefs::internal::kSyncEncryptionBootstrapToken);
  if (IsInitialSyncFeatureSetupComplete()) {
    // When Sync-the-feature gets turned off, the user's encryption bootstrap
    // token should be cleared. However, at this point it's hard to determine
    // the right account, since the user is already signed out. For simplicity,
    // just clear all existing bootstrap tokens (in practice, there will almost
    // always be at most one anyway).
    KeepAccountKeyedPrefValuesOnlyForUsers(
        pref_service_, prefs::internal::kSyncEncryptionBootstrapTokenPerAccount,
        {});
  }
}

CustomPassphraseBootstrapToken SyncPrefs::GetEncryptionBootstrapTokenForAccount(
    const os_crypt_async::Encryptor& encryptor,
    const GaiaId& gaia_id) const {
  if (gaia_id.empty()) {
    return CustomPassphraseBootstrapToken();
  }
  const std::string* account_passphrase =
      pref_service_
          ->GetDict(prefs::internal::kSyncEncryptionBootstrapTokenPerAccount)
          .FindString(signin::GaiaIdHash::FromGaiaId(gaia_id).ToBase64());
  if (!account_passphrase) {
    return CustomPassphraseBootstrapToken();
  }
  return CustomPassphraseBootstrapToken::FromEncryptedPref(*account_passphrase,
                                                           encryptor);
}

void SyncPrefs::SetEncryptionBootstrapTokenForAccount(
    const CustomPassphraseBootstrapToken& token,
    const os_crypt_async::Encryptor& encryptor,
    const GaiaId& gaia_id) {
  CHECK(!gaia_id.empty());
  SetAccountKeyedPrefValue(
      pref_service_, prefs::internal::kSyncEncryptionBootstrapTokenPerAccount,
      signin::GaiaIdHash::FromGaiaId(gaia_id),
      base::Value(token.ToEncryptedPref(encryptor)));
}

void SyncPrefs::ClearEncryptionBootstrapTokenForAccount(const GaiaId& gaia_id) {
  ClearAccountKeyedPrefValue(
      pref_service_, prefs::internal::kSyncEncryptionBootstrapTokenPerAccount,
      signin::GaiaIdHash::FromGaiaId(gaia_id));
}

// static
const char* SyncPrefs::GetPrefNameForTypeForTesting(UserSelectableType type) {
  return GetPrefNameForType(type);
}

// static
const char* SyncPrefs::GetPrefNameForType(UserSelectableType type) {
  switch (type) {
    case UserSelectableType::kBookmarks:
      return prefs::internal::kSyncBookmarks;
    case UserSelectableType::kPreferences:
      return prefs::internal::kSyncPreferences;
    case UserSelectableType::kPasswords:
      return prefs::internal::kSyncPasswords;
    case UserSelectableType::kAutofill:
      return prefs::internal::kSyncAutofill;
    case UserSelectableType::kThemes:
      return prefs::internal::kSyncThemes;
    case UserSelectableType::kHistory:
      return prefs::internal::kSyncHistory;
    case UserSelectableType::kExtensions:
      return prefs::internal::kSyncExtensions;
    case UserSelectableType::kApps:
      return prefs::internal::kSyncApps;
    case UserSelectableType::kReadingList:
      return prefs::internal::kSyncReadingList;
    case UserSelectableType::kTabs:
      return prefs::internal::kSyncTabs;
    case UserSelectableType::kSavedTabGroups:
      return prefs::internal::kSyncSavedTabGroups;
    case UserSelectableType::kPayments:
      return prefs::internal::kSyncPayments;
    case UserSelectableType::kProductComparison:
      return prefs::internal::kSyncProductComparison;
    case UserSelectableType::kCookies:
      return prefs::internal::kSyncCookies;
  }
  NOTREACHED();
}

// static
void SyncPrefs::SetTypeDisabledByPolicy(PrefValueMap* policy_prefs,
                                        UserSelectableType type) {
  const char* pref_name = syncer::SyncPrefs::GetPrefNameForType(type);
  CHECK(pref_name);
  CHECK(policy_prefs);
  policy_prefs->SetValue(pref_name, base::Value(false));
}

// static void
void SyncPrefs::SetTypeDisabledByCustodian(PrefValueMap* supervised_user_prefs,
                                           UserSelectableType type) {
  const char* pref_name = syncer::SyncPrefs::GetPrefNameForType(type);
  CHECK(pref_name);
  CHECK(supervised_user_prefs);
  supervised_user_prefs->SetValue(pref_name, base::Value(false));
}

// static
bool SyncPrefs::IsTypeSupportedInTransportMode(UserSelectableType type) {
  // Not all types are supported in transport mode, and many require one or more
  // Features to be enabled.
  switch (type) {
    case UserSelectableType::kBookmarks:
      return base::FeatureList::IsEnabled(
          switches::kSyncEnableBookmarksInTransportMode);
    case UserSelectableType::kReadingList:
      return syncer::IsReadingListAccountStorageEnabled();
    case UserSelectableType::kPreferences:
      if (!base::FeatureList::IsEnabled(
              switches::kEnablePreferencesAccountStorage)) {
        return false;
      }
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
      return IsReplaceSyncPromosWithSignInPromosEnabled();
#else
      // Search engines are behind `UserSelectableType::kPreferences`.
      return base::FeatureList::IsEnabled(
          kSeparateLocalAndAccountSearchEngines);
#endif
    case UserSelectableType::kPasswords:
      return true;
    case UserSelectableType::kAutofill:
      return true;
    case UserSelectableType::kPayments:
      // Always supported, since AUTOFILL_WALLET_DATA is supported in
      // transport mode everywhere.
      return true;
    case UserSelectableType::kHistory:
      return IsReplaceSyncPromosWithSignInPromosEnabled();
    case UserSelectableType::kTabs:
      return IsReplaceSyncPromosWithSignInPromosEnabled();
    case UserSelectableType::kProductComparison:
      return IsReplaceSyncPromosWithSignInPromosEnabled();
    case UserSelectableType::kSavedTabGroups:
      return IsReplaceSyncPromosWithSignInPromosEnabled();
    case UserSelectableType::kExtensions:
#if BUILDFLAG(IS_CHROMEOS)
      return base::FeatureList::IsEnabled(kReplaceSyncPromosWithSignInPromos);
#else
      return true;
#endif  // BUILDFLAG(IS_CHROMEOS)
    case UserSelectableType::kThemes:
#if BUILDFLAG(IS_ANDROID)
      return base::FeatureList::IsEnabled(
          syncer::kNewTabPageCustomizationThemeSync);
#elif BUILDFLAG(IS_IOS)
      // Allow 'Themes' toggle on iOS if the feature is enabled.
      return base::FeatureList::IsEnabled(syncer::kSyncThemesIos);
#else
      return base::FeatureList::IsEnabled(
          syncer::kSeparateLocalAndAccountThemes);
#endif
    case UserSelectableType::kApps:
      return IsReplaceSyncPromosWithSignInPromosEnabled();
    case UserSelectableType::kCookies:
#if BUILDFLAG(IS_CHROMEOS)
      return base::FeatureList::IsEnabled(kReplaceSyncPromosWithSignInPromos);
#else
      // ChromeOS-only type.
      return false;
#endif
  }
  NOTREACHED();
}

void SyncPrefs::OnSyncManagedPrefChanged() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  for (SyncPrefObserver& observer : sync_pref_observers_) {
    observer.OnSyncManagedPrefChange(*pref_sync_managed_);
  }
}

void SyncPrefs::OnSelectedTypesPrefChanged(const std::string& pref_name) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  // If there is a batch update of selected-types prefs ongoing, don't notify
  // observers - the call site will take care of it.
  if (batch_updating_selected_types_) {
    return;
  }

  for (SyncPrefObserver& observer : sync_pref_observers_) {
    observer.OnSelectedTypesPrefChange();
  }
}

// static
void SyncPrefs::RegisterTypeSelectedPref(PrefRegistrySimple* registry,
                                         UserSelectableType type) {
  const char* pref_name = GetPrefNameForType(type);
  DCHECK(pref_name);
  registry->RegisterBooleanPref(pref_name, false);
}

bool SyncPrefs::IsLocalSyncEnabled() const {
  return local_sync_enabled_;
}

int SyncPrefs::GetPassphrasePromptMutedProductVersion() const {
  return pref_service_->GetInteger(
      prefs::internal::kSyncPassphrasePromptMutedProductVersion);
}

void SyncPrefs::SetPassphrasePromptMutedProductVersion(int major_version) {
  pref_service_->SetInteger(
      prefs::internal::kSyncPassphrasePromptMutedProductVersion, major_version);
}

void SyncPrefs::ClearPassphrasePromptMutedProductVersion() {
  pref_service_->ClearPref(
      prefs::internal::kSyncPassphrasePromptMutedProductVersion);
}

bool SyncPrefs::MaybeMigratePrefsForSyncToSigninPart1(
    SyncAccountState account_state,
    const GaiaId& gaia_id) {
  if (!IsReplaceSyncPromosWithSignInPromosEnabled()) {
    // Ensure that the migration runs again when the feature gets enabled.
    pref_service_->ClearPref(prefs::internal::kSyncToSigninMigrationState);
    return false;
  }

  // Don't migrate again if this profile was previously migrated.
  if (pref_service_->GetInteger(prefs::internal::kSyncToSigninMigrationState) !=
      kNotMigrated) {
    return false;
  }

  if (IsLocalSyncEnabled()) {
    // Special case for local sync: There isn't necessarily a signed-in user
    // (even if the SyncAccountState is kSyncing), so just mark the migration as
    // done.
    pref_service_->SetInteger(prefs::internal::kSyncToSigninMigrationState,
                              kMigratedPart2AndFullyDone);
    return false;
  }

  switch (account_state) {
    case SyncAccountState::kNotSignedIn:
    case SyncAccountState::kSyncing: {
      // Nothing to migrate for signed-out or syncing users. Also make sure the
      // second part of the migration does *not* run if a signed-out user does
      // later sign in / turn on sync.
      pref_service_->SetInteger(prefs::internal::kSyncToSigninMigrationState,
                                kMigratedPart2AndFullyDone);
      return false;
    }
    case SyncAccountState::kSignedInWithoutSyncConsent: {
      pref_service_->SetInteger(prefs::internal::kSyncToSigninMigrationState,
                                kMigratedPart1ButNot2);
      CHECK(!gaia_id.empty());
      ScopedDictPrefUpdate update_selected_types_dict(
          pref_service_, prefs::internal::kSelectedTypesPerAccount);
      base::DictValue* account_settings =
          update_selected_types_dict->EnsureDict(
              signin::GaiaIdHash::FromGaiaId(gaia_id).ToBase64());

#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
      // Preserve the user's existing enabled state for Bookmarks, Reading List,
      // and Preferences. Otherwise, use the default value, which will be true
      // after `kReplaceSyncPromosWithSignInPromos`.
      for (UserSelectableType type :
           {UserSelectableType::kBookmarks, UserSelectableType::kReadingList,
            UserSelectableType::kPreferences}) {
        const char* pref_name = GetPrefNameForType(type);
        DCHECK(pref_name);
        const base::Value* value = account_settings->Find(pref_name);
        if (value && value->is_bool()) {
          account_settings->Set(pref_name, value->GetBool());
        }
      }
#else
      // Settings aka preferences always starts out "off" for existing
      // signed-in non-syncing users.
      account_settings->Set(
          GetPrefNameForType(UserSelectableType::kPreferences), false);

      // Bookmarks and reading list remain enabled only if the user previously
      // explicitly opted in, which is represented in the regular account-keyed
      // prefs. However, the default value for new sign-ins may change with
      // `kReplaceSyncPromosWithSignInPromos`, so it is important to grab a
      // snapshot now during migration.
      for (UserSelectableType type :
           {UserSelectableType::kBookmarks, UserSelectableType::kReadingList}) {
        const char* pref_name = GetPrefNameForType(type);
        DCHECK(pref_name);

        const base::Value* value = account_settings->Find(pref_name);
        const bool is_type_on = value && value->is_bool() && value->GetBool();

        // Setting the value explicitly is important to convert absence to
        // false, so it doesn't use the default, which is enabled after
        // `kReplaceSyncPromosWithSignInPromos`.
        account_settings->Set(pref_name, is_type_on);
      }
#endif
      return true;
    }
  }
}

bool SyncPrefs::MaybeMigratePrefsForSyncToSigninPart2(
    const GaiaId& gaia_id,
    bool is_using_explicit_passphrase) {
  // The migration pref shouldn't be set if the feature is disabled, but if it
  // somehow happened, do *not* run the migration, and clear the pref so that
  // the migration will get triggered again once the feature gets enabled again.
  if (!IsReplaceSyncPromosWithSignInPromosEnabled()) {
    pref_service_->ClearPref(prefs::internal::kSyncToSigninMigrationState);
    return false;
  }

  // Only run part 2 of the migration if part 1 has run but part 2 hasn't yet.
  // This ensures that it only runs once.
  if (pref_service_->GetInteger(prefs::internal::kSyncToSigninMigrationState) !=
      kMigratedPart1ButNot2) {
    return false;
  }
  pref_service_->SetInteger(prefs::internal::kSyncToSigninMigrationState,
                            kMigratedPart2AndFullyDone);

  // The actual migration: For explicit-passphrase users, addresses sync gets
  // disabled by default.
  if (is_using_explicit_passphrase && !IsLocalSyncEnabled()) {
    CHECK(!gaia_id.empty());
    SetAccountKeyedPrefDictEntry(
        pref_service_, prefs::internal::kSelectedTypesPerAccount,
        signin::GaiaIdHash::FromGaiaId(gaia_id),
        GetPrefNameForType(UserSelectableType::kAutofill), base::Value(false));
    return true;
  }
  return false;
}

void SyncPrefs::MaybeMigrateCustomPassphrasePref(const GaiaId& gaia_id) {
  if (pref_service_->GetBoolean(
          kSyncEncryptionBootstrapTokenPerAccountMigrationDone)) {
    return;
  }
  pref_service_->SetBoolean(
      kSyncEncryptionBootstrapTokenPerAccountMigrationDone, true);

  if (gaia_id.empty()) {
    // Do not migrate if gaia_id is empty; no signed in user.
    return;
  }

  const std::string& token =
      pref_service_->GetString(prefs::internal::kSyncEncryptionBootstrapToken);
  if (token.empty()) {
    // No custom passphrase is used, or it is not set.
    return;
  }
  SetAccountKeyedPrefValue(
      pref_service_, prefs::internal::kSyncEncryptionBootstrapTokenPerAccount,
      signin::GaiaIdHash::FromGaiaId(gaia_id), base::Value(token));
  return;
}

// static
void SyncPrefs::MigrateGlobalDataTypePrefsToAccount(PrefService* pref_service,
                                                    const GaiaId& gaia_id) {
  CHECK(!gaia_id.empty());

  // Note: This method does *not* ensure that the migration only runs once -
  // that's the caller's responsibility! (In practice, that's
  // MaybeMigrateSyncingUserToSignedIn()).

  ScopedDictPrefUpdate update_selected_types_dict(
      pref_service, prefs::internal::kSelectedTypesPerAccount);
  base::DictValue* account_settings = update_selected_types_dict->EnsureDict(
      signin::GaiaIdHash::FromGaiaId(gaia_id).ToBase64());

  // The values of the "global" data type prefs get copied to the
  // account-specific ones.
  bool everything_enabled =
      pref_service->GetBoolean(prefs::internal::kSyncKeepEverythingSynced);
  // Most of the per-account prefs default to "true", so nothing needs to be
  // done for those. The exceptions are History, Tabs and Saved Tab Groups,
  // which need to be enabled explicitly, and should remain enabled only if they
  // were enabled previously, so they're specially tracked here.
  bool history_enabled = everything_enabled;
  bool tabs_enabled = everything_enabled;
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
  // Saved Tab Groups user toggle is only used on desktop.
  bool saved_tab_groups_enabled = everything_enabled;
  // Explicitly set the extensions toggle, which otherwise requires an explicit
  // sign-in to be enabled by default. This is to specifically handle the case
  // when `syncer::kExplicitSigninForExtension` is true.
  bool extensions_enabled = everything_enabled;
  // Explicitly set the bookmarks toggle, which otherwise requires an explicit
  // sign-in to be enabled by default. This is to specifically handle the case
  // when `syncer::kExplicitSigninForBookmarks` is true.
  bool bookmarks_enabled = everything_enabled;
#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
  if (everything_enabled) {
    // On desktop, Passwords is considered disabled by default and
    // so also needs to be enabled explicitly.
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
    // TODO(b/314773312): Remove this when Uno is enabled.
    account_settings->Set(GetPrefNameForType(UserSelectableType::kPasswords),
                          true);
#endif
  } else {
    // "Sync everything" is off, so copy over the individual value for each
    // type.
    for (UserSelectableType type : UserSelectableTypeSet::All()) {
      const char* pref_name = GetPrefNameForType(type);
      CHECK(pref_name);
      // Copy value from global to per-account pref.
      account_settings->Set(pref_name, pref_service->GetBoolean(pref_name));
    }
    history_enabled = pref_service->GetBoolean(
        GetPrefNameForType(UserSelectableType::kHistory));
    tabs_enabled =
        pref_service->GetBoolean(GetPrefNameForType(UserSelectableType::kTabs));
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
    saved_tab_groups_enabled = pref_service->GetBoolean(
        GetPrefNameForType(UserSelectableType::kSavedTabGroups));
    extensions_enabled = pref_service->GetBoolean(
        GetPrefNameForType(UserSelectableType::kExtensions));
    bookmarks_enabled = pref_service->GetBoolean(
        GetPrefNameForType(UserSelectableType::kBookmarks));
#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
  }
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
  // On mobile, History and Tabs remain enabled only if they were both
  // enabled previously.
  account_settings->Set(GetPrefNameForType(UserSelectableType::kHistory),
                        history_enabled && tabs_enabled);
  account_settings->Set(GetPrefNameForType(UserSelectableType::kTabs),
                        history_enabled && tabs_enabled);
#else
  // On desktop, History, Tabs and Saved Tab Groups carry over their individual
  // values.
  account_settings->Set(GetPrefNameForType(UserSelectableType::kHistory),
                        history_enabled);
  account_settings->Set(GetPrefNameForType(UserSelectableType::kTabs),
                        tabs_enabled);
  account_settings->Set(GetPrefNameForType(UserSelectableType::kBookmarks),
                        bookmarks_enabled);
  account_settings->Set(GetPrefNameForType(UserSelectableType::kSavedTabGroups),
                        saved_tab_groups_enabled);
  account_settings->Set(GetPrefNameForType(UserSelectableType::kExtensions),
                        extensions_enabled);
#endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
  // Another special case: For custom passphrase users, "Addresses and more"
  // gets disabled by default. The reason is that for syncing custom passphrase
  // users, this toggle mapped to the legacy AUTOFILL_PROFILE type (which
  // supported custom passphrase), but for migrated users it maps to
  // CONTACT_INFO (which does not). This is only done on Mobile because on
  // Desktop the strings already mention that the addresses are not encrypted
  // with the passphrase.
  std::optional<PassphraseType> passphrase_type = ProtoPassphraseInt32ToEnum(
      pref_service->GetInteger(prefs::internal::kSyncCachedPassphraseType));
  if (passphrase_type.has_value() && IsExplicitPassphrase(*passphrase_type)) {
    account_settings->Set(GetPrefNameForType(UserSelectableType::kAutofill),
                          false);
  }
#endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)

  // Usually, the "SyncToSignin" migration (aka phase 2) will have completed
  // previously. But just in case it hasn't, make sure it doesn't run in the
  // future - it's not neeced, and in fact it might mess up some of the things
  // that were just migrated here.
  pref_service->SetInteger(prefs::internal::kSyncToSigninMigrationState,
                           kMigratedPart2AndFullyDone);
}

void SyncPrefs::MarkPartialSyncToSigninMigrationFullyDone() {
  // If the first part of the migration has run, but the second part has not,
  // then mark the migration as fully done - at this point (after signout)
  // there's no more need for any migration.
  // In all other cases (migration never even started, or completed fully),
  // nothing to be done here.
  if (pref_service_->GetInteger(prefs::internal::kSyncToSigninMigrationState) ==
      kMigratedPart1ButNot2) {
    pref_service_->SetInteger(prefs::internal::kSyncToSigninMigrationState,
                              kMigratedPart2AndFullyDone);
  }
}

bool SyncPrefs::IsTypeSelectedByDefaultInTransportMode(
    UserSelectableType type,
    const GaiaId& gaia_id) const {
  switch (type) {
    case UserSelectableType::kPayments:
    case UserSelectableType::kPasswords:
    case UserSelectableType::kAutofill:
      return true;
    case UserSelectableType::kHistory:
    case UserSelectableType::kTabs:
    case UserSelectableType::kSavedTabGroups:
#if BUILDFLAG(IS_CHROMEOS)
      return IsReplaceSyncPromosWithSignInPromosEnabled();
#else
      // History and tabs require a separate opt in.
      return false;
#endif
    case UserSelectableType::kBookmarks:
    case UserSelectableType::kReadingList:
      return IsBookmarksSelectedByDefaultInTransportMode(*pref_service_,
                                                         gaia_id);
    case UserSelectableType::kPreferences:
    case UserSelectableType::kThemes:
      return IsReplaceSyncPromosWithSignInPromosEnabled() ||
             pref_service_->GetBoolean(
                 ::prefs::kPrefsThemesSearchEnginesAccountStorageEnabled);
    case UserSelectableType::kExtensions:
      return IsExtensionsSelectedByDefaultInTransportMode(*pref_service_,
                                                          gaia_id);
    case UserSelectableType::kApps:
    case UserSelectableType::kProductComparison:
    case UserSelectableType::kCookies:
      // All other types are always enabled by default with
      // kReplaceSyncPromosWithSignInPromos.
      return IsReplaceSyncPromosWithSignInPromosEnabled();
  }
  NOTREACHED();
}

}  // namespace syncer
