diff --git a/browser/brave_ads/BUILD.gn b/browser/brave_ads/BUILD.gn index 91bb2226532..c97955341e3 100644 --- a/browser/brave_ads/BUILD.gn +++ b/browser/brave_ads/BUILD.gn @@ -11,6 +11,7 @@ source_set("brave_ads") { "ads_service_delegate.h", "ads_service_factory.h", "analytics/p3a/brave_stats_helper.h", + "virtual_pref_provider_delegate.h", ] public_deps = [ @@ -47,6 +48,7 @@ source_set("impl") { "application_state/notification_helper/notification_helper.h", "application_state/notification_helper/notification_helper_impl.cc", "application_state/notification_helper/notification_helper_impl.h", + "virtual_pref_provider_delegate.cc", ] deps = [ @@ -63,7 +65,6 @@ source_set("impl") { "//brave/components/brave_adaptive_captcha", "//brave/components/brave_ads/browser/application_state", "//brave/components/p3a_utils", - "//brave/components/skus/browser", "//chrome/browser:browser_process", "//chrome/browser:browser_public_dependencies", "//chrome/browser:primitives", diff --git a/browser/brave_ads/ads_service_delegate.cc b/browser/brave_ads/ads_service_delegate.cc index bb7b9c36005..895a3f673b7 100644 --- a/browser/brave_ads/ads_service_delegate.cc +++ b/browser/brave_ads/ads_service_delegate.cc @@ -5,31 +5,17 @@ #include "brave/browser/brave_ads/ads_service_delegate.h" -#include #include -#include #include "base/check_deref.h" -#include "base/json/json_reader.h" -#include "base/strings/utf_string_conversions.h" -#include "base/version.h" -#include "base/version_info/channel.h" -#include "base/version_info/version_info.h" #include "brave/browser/brave_ads/ad_units/notification_ad/notification_ad_platform_bridge.h" #include "brave/browser/brave_ads/application_state/notification_helper/notification_helper.h" #include "brave/browser/ui/brave_ads/notification_ad.h" #include "brave/components/brave_adaptive_captcha/brave_adaptive_captcha_service.h" -#include "brave/components/brave_ads/core/public/common/locale/locale_util.h" -#include "brave/components/skus/browser/pref_names.h" #include "build/build_config.h" #include "chrome/browser/notifications/notification_display_service.h" #include "chrome/browser/notifications/notification_display_service_factory.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/search_engines/template_url_prepopulate_data_resolver_factory.h" -#include "chrome/common/channel_info.h" -#include "components/search_engines/template_url_data.h" -#include "components/search_engines/template_url_prepopulate_data.h" -#include "components/search_engines/template_url_prepopulate_data_resolver.h" #include "ui/message_center/public/cpp/notification.h" #include "ui/message_center/public/cpp/notification_types.h" #include "ui/message_center/public/cpp/notifier_id.h" @@ -48,102 +34,7 @@ namespace brave_ads { namespace { - -constexpr char kSkuEnvironmentPrefix[] = "skus:"; -constexpr char kSkuOrdersKey[] = "orders"; -constexpr char kSkuOrderLocationKey[] = "location"; -constexpr char kSkuOrderCreatedAtKey[] = "created_at"; -constexpr char kSkuOrderExpiresAtKey[] = "expires_at"; -constexpr char kSkuOrderLastPaidAtKey[] = "last_paid_at"; -constexpr char kSkuOrderStatusKey[] = "status"; constexpr char kNotificationAdUrlPrefix[] = "https://www.brave.com/ads/?"; - -int GetVersionComponent(size_t index) { - const base::Version& version = version_info::GetVersion(); - const std::vector& version_components = version.components(); - return index < version_components.size() - ? static_cast(version_components[index]) - : 0; -} - -int GetMajorVersion() { - return GetVersionComponent(0); -} - -int GetMinorVersion() { - return GetVersionComponent(1); -} - -int GetBuildVersion() { - return GetVersionComponent(2); -} - -int GetPatchVersion() { - return GetVersionComponent(3); -} - -bool IsMobilePlatform() { - std::string_view operating_system_name = version_info::GetOSType(); - return operating_system_name == "Android" || operating_system_name == "iOS"; -} - -std::string StripSkuEnvironmentPrefix(const std::string& environment) { - const size_t pos = environment.find(':'); - return environment.substr(pos + 1); -} - -std::string NormalizeSkuStatus(const std::string& status) { - // Normalize the status field to use consistent (US) spelling, as the JSON - // source localizes it (e.g., "cancelled" vs "canceled"). - return status == "cancelled" ? "canceled" : status; -} - -base::Value::Dict ParseSkuOrder(const base::Value::Dict& dict) { - base::Value::Dict order; - - if (const std::string* const created_at = - dict.FindString(kSkuOrderCreatedAtKey)) { - order.Set(kSkuOrderCreatedAtKey, *created_at); - } - - if (const std::string* const expires_at = - dict.FindString(kSkuOrderExpiresAtKey)) { - order.Set(kSkuOrderExpiresAtKey, *expires_at); - } - - if (const std::string* const last_paid_at = - dict.FindString(kSkuOrderLastPaidAtKey)) { - order.Set(kSkuOrderLastPaidAtKey, *last_paid_at); - } - - if (const std::string* const status = dict.FindString(kSkuOrderStatusKey)) { - const std::string normalized_status = NormalizeSkuStatus(*status); - order.Set(kSkuOrderStatusKey, normalized_status); - } - - return order; -} - -base::Value::Dict ParseSkuOrders(const base::Value::Dict& dict) { - base::Value::Dict orders; - - for (const auto [/*id*/ _, value] : dict) { - const base::Value::Dict* const order = value.GetIfDict(); - if (!order) { - continue; - } - - const std::string* const location = order->FindString(kSkuOrderLocationKey); - if (!location || location->empty()) { - continue; - } - - orders.Set(*location, ParseSkuOrder(*order)); - } - - return orders; -} - } // namespace AdsServiceDelegate::AdsServiceDelegate( @@ -161,49 +52,6 @@ AdsServiceDelegate::AdsServiceDelegate( AdsServiceDelegate::~AdsServiceDelegate() {} -std::string AdsServiceDelegate::GetDefaultSearchEngineName() { - auto* prepopulate_data_resolver = - TemplateURLPrepopulateData::ResolverFactory::GetForProfile(&*profile_); - const auto template_url_data = prepopulate_data_resolver->GetFallbackSearch(); - const std::u16string& default_search_engine_name = - template_url_data ? template_url_data->short_name() : u""; - return base::UTF16ToUTF8(default_search_engine_name); -} - -base::Value::Dict AdsServiceDelegate::GetSkus() const { - base::Value::Dict skus; - - if (!local_state_->FindPreference(skus::prefs::kSkusState)) { - // No SKUs in local state. - return skus; - } - - const base::Value::Dict& skus_state = - local_state_->GetDict(skus::prefs::kSkusState); - for (const auto [environment, value] : skus_state) { - if (!environment.starts_with(kSkuEnvironmentPrefix)) { - continue; - } - - // Deserialize the SKUs data from a JSON string stored in local state into a - // dictionary object for further processing. - std::optional sku_state = - base::JSONReader::ReadDict(value.GetString()); - if (!sku_state) { - continue; - } - - const base::Value::Dict* const orders = sku_state->FindDict(kSkuOrdersKey); - if (!orders) { - continue; - } - - skus.Set(StripSkuEnvironmentPrefix(environment), ParseSkuOrders(*orders)); - } - - return skus; -} - void AdsServiceDelegate::OpenNewTabWithUrl(const GURL& url) { #if BUILDFLAG(IS_ANDROID) // ServiceTabLauncher can currently only launch new tabs @@ -327,30 +175,6 @@ bool AdsServiceDelegate::IsFullScreenMode() { #endif } -base::Value::Dict AdsServiceDelegate::GetVirtualPrefs() { - return base::Value::Dict() - .Set("[virtual]:browser", - base::Value::Dict() - .Set("build_channel", - version_info::GetChannelString(chrome::GetChannel())) - .Set("version", version_info::GetVersionNumber()) - .Set("major_version", GetMajorVersion()) - .Set("minor_version", GetMinorVersion()) - .Set("build_version", GetBuildVersion()) - .Set("patch_version", GetPatchVersion())) - .Set("[virtual]:operating_system", - base::Value::Dict() - .Set("locale", base::Value::Dict() - .Set("language", CurrentLanguageCode()) - .Set("region", CurrentCountryCode())) - .Set("is_mobile_platform", IsMobilePlatform()) - .Set("name", version_info::GetOSType())) - .Set( - "[virtual]:search_engine", - base::Value::Dict().Set("default_name", GetDefaultSearchEngineName())) - .Set("[virtual]:skus", GetSkus()); -} - NotificationDisplayService* AdsServiceDelegate::GetNotificationDisplayService() { return NotificationDisplayServiceFactory::GetForProfile(&*profile_); diff --git a/browser/brave_ads/ads_service_delegate.h b/browser/brave_ads/ads_service_delegate.h index dfe26a4538c..07af65a78ab 100644 --- a/browser/brave_ads/ads_service_delegate.h +++ b/browser/brave_ads/ads_service_delegate.h @@ -11,7 +11,6 @@ #include "base/memory/raw_ptr.h" #include "base/memory/raw_ref.h" -#include "base/values.h" #include "brave/components/brave_ads/core/browser/service/ads_service.h" #include "components/prefs/pref_service.h" @@ -42,10 +41,6 @@ class AdsServiceDelegate : public AdsService::Delegate { ~AdsServiceDelegate() override; - std::string GetDefaultSearchEngineName(); - - base::Value::Dict GetSkus() const; - // AdsService::Delegate: void MaybeInitNotificationHelper(base::OnceClosure callback) override; bool CanShowSystemNotificationsWhileBrowserIsBackgrounded() override; @@ -64,8 +59,6 @@ class AdsServiceDelegate : public AdsService::Delegate { void OpenNewTabWithUrl(const GURL& url) override; bool IsFullScreenMode() override; - base::Value::Dict GetVirtualPrefs() override; - private: NotificationDisplayService* GetNotificationDisplayService(); diff --git a/browser/brave_ads/ads_service_factory.cc b/browser/brave_ads/ads_service_factory.cc index 15fd6ffac69..62a53367fa4 100644 --- a/browser/brave_ads/ads_service_factory.cc +++ b/browser/brave_ads/ads_service_factory.cc @@ -15,6 +15,7 @@ #include "brave/browser/brave_ads/device_id/device_id_impl.h" #include "brave/browser/brave_ads/services/bat_ads_service_factory_impl.h" #include "brave/browser/brave_ads/tooltips/ads_tooltips_delegate_impl.h" +#include "brave/browser/brave_ads/virtual_pref_provider_delegate.h" #include "brave/browser/brave_browser_process.h" #include "brave/browser/brave_rewards/rewards_service_factory.h" #include "brave/browser/brave_rewards/rewards_util.h" @@ -98,6 +99,7 @@ AdsServiceFactory::BuildServiceInstanceForBrowserContext( return std::make_unique( std::move(delegate), profile->GetPrefs(), g_browser_process->local_state(), + std::make_unique(*profile), profile->GetDefaultStoragePartition() ->GetURLLoaderFactoryForBrowserProcess(), brave::GetChannelName(), profile->GetPath(), CreateAdsTooltipsDelegate(), diff --git a/browser/brave_ads/virtual_pref_provider_delegate.cc b/browser/brave_ads/virtual_pref_provider_delegate.cc new file mode 100644 index 00000000000..cc14b8537a6 --- /dev/null +++ b/browser/brave_ads/virtual_pref_provider_delegate.cc @@ -0,0 +1,37 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/brave_ads/virtual_pref_provider_delegate.h" + +#include "base/strings/utf_string_conversions.h" +#include "base/version_info/channel.h" +#include "base/version_info/version_info.h" +#include "chrome/browser/search_engines/template_url_prepopulate_data_resolver_factory.h" +#include "chrome/common/channel_info.h" +#include "components/search_engines/template_url_data.h" +#include "components/search_engines/template_url_prepopulate_data.h" +#include "components/search_engines/template_url_prepopulate_data_resolver.h" + +namespace brave_ads { + +VirtualPrefProviderDelegate::VirtualPrefProviderDelegate(Profile& profile) + : profile_(profile) {} + +VirtualPrefProviderDelegate::~VirtualPrefProviderDelegate() = default; + +std::string VirtualPrefProviderDelegate::GetChannel() const { + return std::string(version_info::GetChannelString(chrome::GetChannel())); +} + +std::string VirtualPrefProviderDelegate::GetDefaultSearchEngineName() const { + auto* prepopulate_data_resolver = + TemplateURLPrepopulateData::ResolverFactory::GetForProfile(&*profile_); + const auto template_url_data = prepopulate_data_resolver->GetFallbackSearch(); + const std::u16string& default_search_engine_name = + template_url_data ? template_url_data->short_name() : u""; + return base::UTF16ToUTF8(default_search_engine_name); +} + +} // namespace brave_ads diff --git a/browser/brave_ads/virtual_pref_provider_delegate.h b/browser/brave_ads/virtual_pref_provider_delegate.h new file mode 100644 index 00000000000..0dfb9f40b86 --- /dev/null +++ b/browser/brave_ads/virtual_pref_provider_delegate.h @@ -0,0 +1,38 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_BROWSER_BRAVE_ADS_VIRTUAL_PREF_PROVIDER_DELEGATE_H_ +#define BRAVE_BROWSER_BRAVE_ADS_VIRTUAL_PREF_PROVIDER_DELEGATE_H_ + +#include + +#include "base/memory/raw_ref.h" +#include "brave/components/brave_ads/core/browser/service/virtual_pref_provider.h" + +class Profile; + +namespace brave_ads { + +class VirtualPrefProviderDelegate : public VirtualPrefProvider::Delegate { + public: + explicit VirtualPrefProviderDelegate(Profile& profile); + + VirtualPrefProviderDelegate(const VirtualPrefProviderDelegate&) = delete; + VirtualPrefProviderDelegate& operator=(const VirtualPrefProviderDelegate&) = + delete; + + ~VirtualPrefProviderDelegate() override; + + std::string GetChannel() const override; + + std::string GetDefaultSearchEngineName() const override; + + private: + const raw_ref profile_; +}; + +} // namespace brave_ads + +#endif // BRAVE_BROWSER_BRAVE_ADS_VIRTUAL_PREF_PROVIDER_DELEGATE_H_ diff --git a/chromium_src/ios/chrome/browser/profile/model/keyed_service_factories.mm b/chromium_src/ios/chrome/browser/profile/model/keyed_service_factories.mm index 77fd7ae5c29..80939f54439 100644 --- a/chromium_src/ios/chrome/browser/profile/model/keyed_service_factories.mm +++ b/chromium_src/ios/chrome/browser/profile/model/keyed_service_factories.mm @@ -56,6 +56,7 @@ #include "ios/chrome/browser/safe_browsing/model/safe_browsing_metrics_collector_factory.h" #include "ios/chrome/browser/saved_tab_groups/model/tab_group_service_factory.h" #include "ios/chrome/browser/saved_tab_groups/model/tab_group_sync_service_factory.h" +#include "ios/chrome/browser/search_engines/model/template_url_prepopulate_data_resolver_factory.h" #include "ios/chrome/browser/search_engines/model/template_url_service_factory.h" #include "ios/chrome/browser/segmentation_platform/model/segmentation_platform_service_factory.h" #include "ios/chrome/browser/sessions/model/session_restoration_service_factory.h" @@ -100,6 +101,7 @@ void EnsureProfileKeyedServiceFactoriesBuilt() { ios::HostContentSettingsMapFactory::GetInstance(); ios::LocalOrSyncableBookmarkSyncServiceFactory::GetInstance(); ios::PasswordManagerLogRouterFactory::GetInstance(); + ios::TemplateURLPrepopulateDataResolverFactory::GetInstance(); ios::TemplateURLServiceFactory::GetInstance(); ios::TopSitesFactory::GetInstance(); ios::WebDataServiceFactory::GetInstance(); diff --git a/components/brave_ads/browser/ads_service_impl.cc b/components/brave_ads/browser/ads_service_impl.cc index f2974a16f1c..e2341f3bd72 100644 --- a/components/brave_ads/browser/ads_service_impl.cc +++ b/components/brave_ads/browser/ads_service_impl.cc @@ -6,6 +6,7 @@ #include "brave/components/brave_ads/browser/ads_service_impl.h" #include +#include #include #include @@ -39,6 +40,7 @@ #include "brave/components/brave_ads/browser/tooltips/ads_tooltips_delegate.h" #include "brave/components/brave_ads/core/browser/service/ads_service_observer.h" #include "brave/components/brave_ads/core/browser/service/new_tab_page_ad_prefetcher.h" +#include "brave/components/brave_ads/core/browser/service/virtual_pref_provider.h" #include "brave/components/brave_ads/core/public/ad_units/inline_content_ad/inline_content_ad_value_util.h" #include "brave/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_value_util.h" #include "brave/components/brave_ads/core/public/ad_units/notification_ad/notification_ad_feature.h" @@ -179,6 +181,8 @@ AdsServiceImpl::AdsServiceImpl( std::unique_ptr delegate, PrefService* prefs, PrefService* local_state, + std::unique_ptr + virtual_pref_provider_delegate, scoped_refptr url_loader, std::string_view channel_name, const base::FilePath& profile_path, @@ -192,6 +196,9 @@ AdsServiceImpl::AdsServiceImpl( : AdsService(std::move(delegate)), prefs_(prefs), local_state_(local_state), + virtual_pref_provider_(std::make_unique( + local_state_, + std::move(virtual_pref_provider_delegate))), url_loader_(std::move(url_loader)), channel_name_(channel_name), history_service_(history_service), @@ -1883,7 +1890,7 @@ void AdsServiceImpl::HasLocalStatePrefPath( } void AdsServiceImpl::GetVirtualPrefs(GetVirtualPrefsCallback callback) { - std::move(callback).Run(delegate_->GetVirtualPrefs()); + std::move(callback).Run(virtual_pref_provider_->GetPrefs()); } void AdsServiceImpl::Log(const std::string& file, diff --git a/components/brave_ads/browser/ads_service_impl.h b/components/brave_ads/browser/ads_service_impl.h index 2fe5b3b967a..0fa88d9adbb 100644 --- a/components/brave_ads/browser/ads_service_impl.h +++ b/components/brave_ads/browser/ads_service_impl.h @@ -26,6 +26,7 @@ #include "brave/components/brave_ads/browser/application_state/background_helper.h" #include "brave/components/brave_ads/browser/component_updater/resource_component_observer.h" #include "brave/components/brave_ads/core/browser/service/ads_service.h" +#include "brave/components/brave_ads/core/browser/service/virtual_pref_provider.h" #include "brave/components/brave_ads/core/mojom/brave_ads.mojom.h" #include "brave/components/brave_ads/core/public/ads_callback.h" #include "brave/components/brave_ads/core/public/service/ads_service_callback.h" @@ -68,7 +69,6 @@ class DeviceId; class ResourceComponent; struct NewTabPageAdInfo; class NewTabPageAdPrefetcher; - class AdsServiceImpl final : public AdsService, public bat_ads::mojom::BatAdsClient, public bat_ads::mojom::BatAdsObserver, @@ -81,6 +81,8 @@ class AdsServiceImpl final : public AdsService, std::unique_ptr delegate, PrefService* prefs, PrefService* local_state, + std::unique_ptr + virtual_pref_provider_delegate, scoped_refptr url_loader, std::string_view channel_name, const base::FilePath& profile_path, @@ -465,6 +467,8 @@ class AdsServiceImpl final : public AdsService, const raw_ptr local_state_ = nullptr; // Not owned. + const std::unique_ptr virtual_pref_provider_; + scoped_refptr url_loader_ = nullptr; const std::string channel_name_; diff --git a/components/brave_ads/core/browser/service/BUILD.gn b/components/brave_ads/core/browser/service/BUILD.gn index 646078cbce1..04cc3a904f0 100644 --- a/components/brave_ads/core/browser/service/BUILD.gn +++ b/components/brave_ads/core/browser/service/BUILD.gn @@ -10,6 +10,10 @@ source_set("service") { "ads_service_observer.h", "new_tab_page_ad_prefetcher.cc", "new_tab_page_ad_prefetcher.h", + "virtual_pref_provider.cc", + "virtual_pref_provider.h", + "virtual_pref_provider_util.cc", + "virtual_pref_provider_util.h", ] public_deps = [ @@ -18,20 +22,35 @@ source_set("service") { "//brave/components/brave_ads/core/public:headers", "//brave/components/services/bat_ads/public/interfaces", "//components/keyed_service/core", + "//components/prefs", "//mojo/public/cpp/bindings", ] + + deps = [ + "//base/version_info", + "//brave/components/skus/browser", + ] } source_set("unit_tests") { testonly = true - sources = [ "new_tab_page_ad_prefetcher_unittest.cc" ] + sources = [ + "new_tab_page_ad_prefetcher_unittest.cc", + "virtual_pref_provider_unittest.cc", + ] deps = [ ":service", ":test_support", "//base", + "//base/test:test_support", + "//base/version_info", "//brave/components/brave_ads/core", + "//brave/components/brave_ads/core/public:test_support", + "//brave/components/skus/browser", + "//components/prefs:test_support", + "//testing/gmock", "//testing/gtest", ] } diff --git a/components/brave_ads/core/browser/service/ads_service.h b/components/brave_ads/core/browser/service/ads_service.h index 9f4d0b5916d..635d6eb7635 100644 --- a/components/brave_ads/core/browser/service/ads_service.h +++ b/components/brave_ads/core/browser/service/ads_service.h @@ -50,8 +50,6 @@ class AdsService : public KeyedService { virtual void CloseNotificationAd(const std::string& id, bool is_custom) = 0; virtual void OpenNewTabWithUrl(const GURL& url) = 0; virtual bool IsFullScreenMode() = 0; - - virtual base::Value::Dict GetVirtualPrefs() = 0; }; explicit AdsService(std::unique_ptr delegate); diff --git a/components/brave_ads/core/browser/service/virtual_pref_provider.cc b/components/brave_ads/core/browser/service/virtual_pref_provider.cc new file mode 100644 index 00000000000..b4244b86509 --- /dev/null +++ b/components/brave_ads/core/browser/service/virtual_pref_provider.cc @@ -0,0 +1,155 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_ads/core/browser/service/virtual_pref_provider.h" + +#include + +#include "base/check.h" +#include "base/json/json_reader.h" +#include "base/version_info/version_info.h" +#include "brave/components/brave_ads/core/browser/service/virtual_pref_provider_util.h" +#include "brave/components/brave_ads/core/public/common/locale/locale_util.h" +#include "brave/components/skus/browser/pref_names.h" +#include "components/prefs/pref_service.h" + +namespace brave_ads { + +namespace { + +constexpr char kSkuEnvironmentPrefix[] = "skus:"; +constexpr char kSkuOrdersKey[] = "orders"; +constexpr char kSkuOrderLocationKey[] = "location"; +constexpr char kSkuOrderCreatedAtKey[] = "created_at"; +constexpr char kSkuOrderExpiresAtKey[] = "expires_at"; +constexpr char kSkuOrderLastPaidAtKey[] = "last_paid_at"; +constexpr char kSkuOrderStatusKey[] = "status"; + +std::string StripSkuEnvironmentPrefix(const std::string& environment) { + const size_t pos = environment.find(':'); + return environment.substr(pos + 1); +} + +std::string NormalizeSkuStatus(const std::string& status) { + // Normalize the status field to use consistent (US) spelling, as the JSON + // source localizes it (e.g., "cancelled" vs "canceled"). + return status == "cancelled" ? "canceled" : status; +} + +base::Value::Dict ParseSkuOrder(const base::Value::Dict& dict) { + base::Value::Dict order; + + if (const std::string* const created_at = + dict.FindString(kSkuOrderCreatedAtKey)) { + order.Set(kSkuOrderCreatedAtKey, *created_at); + } + + if (const std::string* const expires_at = + dict.FindString(kSkuOrderExpiresAtKey)) { + order.Set(kSkuOrderExpiresAtKey, *expires_at); + } + + if (const std::string* const last_paid_at = + dict.FindString(kSkuOrderLastPaidAtKey)) { + order.Set(kSkuOrderLastPaidAtKey, *last_paid_at); + } + + if (const std::string* const status = dict.FindString(kSkuOrderStatusKey)) { + const std::string normalized_status = NormalizeSkuStatus(*status); + order.Set(kSkuOrderStatusKey, normalized_status); + } + + return order; +} + +base::Value::Dict ParseSkuOrders(const base::Value::Dict& dict) { + base::Value::Dict orders; + + for (const auto [/*id*/ _, value] : dict) { + const base::Value::Dict* const order = value.GetIfDict(); + if (!order) { + continue; + } + + const std::string* const location = order->FindString(kSkuOrderLocationKey); + if (!location || location->empty()) { + continue; + } + + orders.Set(*location, ParseSkuOrder(*order)); + } + + return orders; +} + +base::Value::Dict GetSkus(PrefService* local_state) { + base::Value::Dict skus; + + if (!local_state->FindPreference(skus::prefs::kSkusState)) { + // No SKUs in local state. + return skus; + } + + const base::Value::Dict& skus_state = + local_state->GetDict(skus::prefs::kSkusState); + for (const auto [environment, value] : skus_state) { + if (!environment.starts_with(kSkuEnvironmentPrefix)) { + continue; + } + + // Deserialize the SKUs data from a JSON string stored in local state into a + // dictionary object for further processing. + std::optional sku_state = + base::JSONReader::ReadDict(value.GetString()); + if (!sku_state) { + continue; + } + + const base::Value::Dict* const orders = sku_state->FindDict(kSkuOrdersKey); + if (!orders) { + continue; + } + + skus.Set(StripSkuEnvironmentPrefix(environment), ParseSkuOrders(*orders)); + } + + return skus; +} + +} // namespace + +VirtualPrefProvider::VirtualPrefProvider(PrefService* local_state, + std::unique_ptr delegate) + : local_state_(local_state), delegate_(std::move(delegate)) { + CHECK(local_state_); + CHECK(delegate_); +} + +VirtualPrefProvider::~VirtualPrefProvider() = default; + +base::Value::Dict VirtualPrefProvider::GetPrefs() { + return base::Value::Dict() + .Set("[virtual]:browser", + base::Value::Dict() + .Set("build_channel", delegate_->GetChannel()) + .Set("version", version_info::GetVersionNumber()) + .Set("major_version", GetMajorVersion()) + .Set("minor_version", GetMinorVersion()) + .Set("build_version", GetBuildVersion()) + .Set("patch_version", GetPatchVersion())) + .Set("[virtual]:operating_system", + base::Value::Dict() + .Set("locale", base::Value::Dict() + .Set("language", CurrentLanguageCode()) + .Set("region", CurrentCountryCode())) + .Set("is_mobile_platform", IsMobilePlatform()) + .Set("name", version_info::GetOSType())) + .Set("[virtual]:search_engine", + base::Value::Dict().Set("default_name", + delegate_->GetDefaultSearchEngineName())) + .Set("[virtual]:skus", GetSkus(local_state_)); +} + +} // namespace brave_ads diff --git a/components/brave_ads/core/browser/service/virtual_pref_provider.h b/components/brave_ads/core/browser/service/virtual_pref_provider.h new file mode 100644 index 00000000000..5f19dd7f855 --- /dev/null +++ b/components/brave_ads/core/browser/service/virtual_pref_provider.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_BROWSER_SERVICE_VIRTUAL_PREF_PROVIDER_H_ +#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_BROWSER_SERVICE_VIRTUAL_PREF_PROVIDER_H_ + +#include +#include + +#include "base/memory/raw_ptr.h" +#include "base/values.h" + +class PrefService; + +namespace brave_ads { + +class VirtualPrefProvider final { + public: + class Delegate { + public: + virtual ~Delegate() = default; + + virtual std::string GetChannel() const = 0; + + virtual std::string GetDefaultSearchEngineName() const = 0; + }; + + VirtualPrefProvider(PrefService* local_state, + std::unique_ptr delegate); + + VirtualPrefProvider(const VirtualPrefProvider&) = delete; + VirtualPrefProvider& operator=(const VirtualPrefProvider&) = delete; + + ~VirtualPrefProvider(); + + base::Value::Dict GetPrefs(); + + private: + const raw_ptr local_state_ = nullptr; // Not owned. + const std::unique_ptr delegate_; +}; + +} // namespace brave_ads + +#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_BROWSER_SERVICE_VIRTUAL_PREF_PROVIDER_H_ diff --git a/components/brave_ads/core/browser/service/virtual_pref_provider_unittest.cc b/components/brave_ads/core/browser/service/virtual_pref_provider_unittest.cc new file mode 100644 index 00000000000..3720ccecb5d --- /dev/null +++ b/components/brave_ads/core/browser/service/virtual_pref_provider_unittest.cc @@ -0,0 +1,229 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_ads/core/browser/service/virtual_pref_provider.h" + +#include +#include +#include + +#include "base/memory/raw_ptr.h" +#include "base/test/values_test_util.h" +#include "base/values.h" +#include "base/version_info/version_info.h" +#include "brave/components/brave_ads/core/browser/service/virtual_pref_provider_util.h" +#include "brave/components/brave_ads/core/public/common/locale/scoped_locale_for_testing.h" +#include "brave/components/skus/browser/pref_names.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/testing_pref_service.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +// npm run test -- brave_unit_tests --filter=BraveAds* + +namespace brave_ads { + +class VirtualPrefProviderDelegateMock : public VirtualPrefProvider::Delegate { + public: + MOCK_METHOD(std::string, GetChannel, (), (const)); + + MOCK_METHOD(std::string, GetDefaultSearchEngineName, (), (const)); +}; + +class VirtualPrefProviderTest : public ::testing::Test { + public: + VirtualPrefProviderTest() { + auto delegate = std::make_unique(); + delegate_ = delegate.get(); + provider_ = std::make_unique(&pref_service_, + std::move(delegate)); + + pref_service_.registry()->RegisterDictionaryPref(skus::prefs::kSkusState); + } + + ~VirtualPrefProviderTest() override { + // Reset delegate to avoid dangling pointer. + delegate_ = nullptr; + } + + TestingPrefServiceSimple& pref_service() { return pref_service_; } + + VirtualPrefProviderDelegateMock& delegate() const { return *delegate_; } + + VirtualPrefProvider& provider() const { return *provider_; } + + private: + TestingPrefServiceSimple pref_service_; + raw_ptr delegate_ = nullptr; + std::unique_ptr provider_; +}; + +TEST_F(VirtualPrefProviderTest, BrowserBuildChannel) { + // Arrange + EXPECT_CALL(delegate(), GetChannel).WillOnce(testing::Return("release")); + + // Act + const base::Value::Dict virtual_prefs = provider().GetPrefs(); + const std::string* build_channel = + virtual_prefs.FindStringByDottedPath("[virtual]:browser.build_channel"); + ASSERT_TRUE(build_channel); + + // Assert + EXPECT_EQ(*build_channel, "release"); +} + +TEST_F(VirtualPrefProviderTest, BrowserVersion) { + // Act + const base::Value::Dict virtual_prefs = provider().GetPrefs(); + const std::string* version = + virtual_prefs.FindStringByDottedPath("[virtual]:browser.version"); + ASSERT_TRUE(version); + + // Assert + EXPECT_EQ(*version, version_info::GetVersionNumber()); +} + +TEST_F(VirtualPrefProviderTest, BrowserMajorVersion) { + // Act + const base::Value::Dict virtual_prefs = provider().GetPrefs(); + std::optional major_version = + virtual_prefs.FindIntByDottedPath("[virtual]:browser.major_version"); + + // Assert + EXPECT_EQ(major_version, GetMajorVersion()); +} + +TEST_F(VirtualPrefProviderTest, BrowserMinorVersion) { + // Act + const base::Value::Dict virtual_prefs = provider().GetPrefs(); + std::optional minor_version = + virtual_prefs.FindIntByDottedPath("[virtual]:browser.minor_version"); + + // Assert + EXPECT_EQ(minor_version, GetMinorVersion()); +} + +TEST_F(VirtualPrefProviderTest, BrowserBuildVersion) { + // Act + const base::Value::Dict virtual_prefs = provider().GetPrefs(); + std::optional build_version = + virtual_prefs.FindIntByDottedPath("[virtual]:browser.build_version"); + + // Assert + EXPECT_EQ(build_version, GetBuildVersion()); +} + +TEST_F(VirtualPrefProviderTest, BrowserPatchVersion) { + // Act + const base::Value::Dict virtual_prefs = provider().GetPrefs(); + std::optional patch_version = + virtual_prefs.FindIntByDottedPath("[virtual]:browser.patch_version"); + + // Assert + EXPECT_EQ(patch_version, GetPatchVersion()); +} + +TEST_F(VirtualPrefProviderTest, OperatingSystemLocaleLanguage) { + // Arrange + const test::ScopedCurrentLanguageCode scoped_current_language_code{"en"}; + + // Act + const base::Value::Dict virtual_prefs = provider().GetPrefs(); + const std::string* language = virtual_prefs.FindStringByDottedPath( + "[virtual]:operating_system.locale.language"); + ASSERT_TRUE(language); + + // Assert + EXPECT_EQ(*language, "en"); +} + +TEST_F(VirtualPrefProviderTest, OperatingSystemLocaleRegion) { + // Arrange + const test::ScopedCurrentCountryCode scoped_current_country_code{"KY"}; + + // Act + const base::Value::Dict virtual_prefs = provider().GetPrefs(); + const std::string* region = virtual_prefs.FindStringByDottedPath( + "[virtual]:operating_system.locale.region"); + ASSERT_TRUE(region); + + // Assert + EXPECT_EQ(*region, "KY"); +} + +TEST_F(VirtualPrefProviderTest, OperatingSystemIsMobilePlatform) { + // Act + const base::Value::Dict virtual_prefs = provider().GetPrefs(); + std::optional is_mobile_platform = virtual_prefs.FindBoolByDottedPath( + "[virtual]:operating_system.is_mobile_platform"); + + // Assert + EXPECT_EQ(is_mobile_platform, IsMobilePlatform()); +} + +TEST_F(VirtualPrefProviderTest, OperatingSystemName) { + // Act + const base::Value::Dict virtual_prefs = provider().GetPrefs(); + const std::string* name = + virtual_prefs.FindStringByDottedPath("[virtual]:operating_system.name"); + ASSERT_TRUE(name); + + // Assert + EXPECT_EQ(*name, version_info::GetOSType()); +} + +TEST_F(VirtualPrefProviderTest, SearchEngineDefaultName) { + // Arrange + EXPECT_CALL(delegate(), GetDefaultSearchEngineName) + .WillOnce(testing::Return("Brave")); + + // Act + const base::Value::Dict virtual_prefs = provider().GetPrefs(); + const std::string* default_search_engine_name = + virtual_prefs.FindStringByDottedPath( + "[virtual]:search_engine.default_name"); + ASSERT_TRUE(default_search_engine_name); + + // Assert + EXPECT_EQ(*default_search_engine_name, "Brave"); +} + +TEST_F(VirtualPrefProviderTest, PrefsWithSkus) { + // Arrange + pref_service().SetDict(skus::prefs::kSkusState, + base::Value::Dict().Set("skus:development", R"JSON({ + "orders": { + "f24787ab-7bc3-46b9-bc05-65befb360cb8": { + "created_at": "2023-10-24T16:00:57.902289", + "expires_at": "2023-12-24T17:03:59.030987", + "last_paid_at": "2023-11-24T17:03:59.030987", + "location": "leo.brave.com", + "status": "paid" + } + } + })JSON")); + + // Act + const base::Value::Dict virtual_prefs = provider().GetPrefs(); + const base::Value::Dict* skus = virtual_prefs.FindDict("[virtual]:skus"); + ASSERT_TRUE(skus); + + // Assert + const base::Value::Dict expected_skus = base::test::ParseJsonDict( + R"JSON( + { + "development": { + "leo.brave.com": { + "created_at": "2023-10-24T16:00:57.902289", + "expires_at": "2023-12-24T17:03:59.030987", + "last_paid_at": "2023-11-24T17:03:59.030987", + "status": "paid" + } + } + })JSON"); + EXPECT_EQ(expected_skus, *skus); +} + +} // namespace brave_ads diff --git a/components/brave_ads/core/browser/service/virtual_pref_provider_util.cc b/components/brave_ads/core/browser/service/virtual_pref_provider_util.cc new file mode 100644 index 00000000000..c01b3c2a51a --- /dev/null +++ b/components/brave_ads/core/browser/service/virtual_pref_provider_util.cc @@ -0,0 +1,50 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_ads/core/browser/service/virtual_pref_provider_util.h" + +#include +#include +#include + +#include "base/version.h" +#include "base/version_info/version_info.h" + +namespace brave_ads { + +namespace { + +int GetVersionComponent(size_t index) { + const base::Version& version = version_info::GetVersion(); + const std::vector& version_components = version.components(); + return index < version_components.size() + ? static_cast(version_components[index]) + : 0; +} + +} // namespace + +int GetMajorVersion() { + return GetVersionComponent(0); +} + +int GetMinorVersion() { + return GetVersionComponent(1); +} + +int GetBuildVersion() { + return GetVersionComponent(2); +} + +int GetPatchVersion() { + return GetVersionComponent(3); +} + +bool IsMobilePlatform() { + std::string_view operating_system_name = version_info::GetOSType(); + return operating_system_name == "Android" || operating_system_name == "iOS"; +} + +} // namespace brave_ads diff --git a/components/brave_ads/core/browser/service/virtual_pref_provider_util.h b/components/brave_ads/core/browser/service/virtual_pref_provider_util.h new file mode 100644 index 00000000000..e1c1391eddc --- /dev/null +++ b/components/brave_ads/core/browser/service/virtual_pref_provider_util.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_BROWSER_SERVICE_VIRTUAL_PREF_PROVIDER_UTIL_H_ +#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_BROWSER_SERVICE_VIRTUAL_PREF_PROVIDER_UTIL_H_ + +namespace brave_ads { + +int GetMajorVersion(); + +int GetMinorVersion(); + +int GetBuildVersion(); + +int GetPatchVersion(); + +bool IsMobilePlatform(); + +} // namespace brave_ads + +#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_BROWSER_SERVICE_VIRTUAL_PREF_PROVIDER_UTIL_H_ diff --git a/components/brave_ads/core/public/BUILD.gn b/components/brave_ads/core/public/BUILD.gn index f33bab27b74..ee1bd90919f 100644 --- a/components/brave_ads/core/public/BUILD.gn +++ b/components/brave_ads/core/public/BUILD.gn @@ -57,3 +57,9 @@ source_set("headers") { public_deps = [ "//brave/components/brave_ads/core/mojom" ] } + +source_set("test_support") { + testonly = true + + sources = [ "common/locale/scoped_locale_for_testing.h" ] +} diff --git a/components/brave_ads/core/test/BUILD.gn b/components/brave_ads/core/test/BUILD.gn index be80da0c70a..5279951d377 100644 --- a/components/brave_ads/core/test/BUILD.gn +++ b/components/brave_ads/core/test/BUILD.gn @@ -660,7 +660,6 @@ source_set("brave_ads_unit_tests") { "//brave/components/brave_ads/core/internal/user_engagement/site_visit/site_visit_observer_mock.h", "//brave/components/brave_ads/core/internal/user_engagement/site_visit/site_visit_unittest.cc", "//brave/components/brave_ads/core/internal/user_engagement/site_visit/site_visit_util_unittest.cc", - "//brave/components/brave_ads/core/public/common/locale/scoped_locale_for_testing.h", ] deps = [ @@ -668,6 +667,7 @@ source_set("brave_ads_unit_tests") { "//brave/components/brave_ads/core", "//brave/components/brave_ads/core/browser/service:unit_tests", "//brave/components/brave_ads/core/internal", + "//brave/components/brave_ads/core/public:test_support", "//brave/components/brave_news/common", "//brave/components/brave_rewards/core", "//brave/components/challenge_bypass_ristretto", diff --git a/ios/browser/api/ads/DEPS b/ios/browser/api/ads/DEPS index 6e01e01d936..13d4340b5f7 100644 --- a/ios/browser/api/ads/DEPS +++ b/ios/browser/api/ads/DEPS @@ -1,4 +1,5 @@ include_rules = [ + "+brave/components/brave_ads/core/browser", "+brave/components/brave_ads/core/mojom", "+brave/components/brave_ads/core/public", "+brave/components/brave_news/common", diff --git a/ios/browser/api/ads/brave_ads.mm b/ios/browser/api/ads/brave_ads.mm index e0360d9c684..898e8874cd4 100644 --- a/ios/browser/api/ads/brave_ads.mm +++ b/ios/browser/api/ads/brave_ads.mm @@ -28,6 +28,7 @@ #include "base/types/optional_ref.h" #include "base/values.h" #import "brave/build/ios/mojom/cpp_transformations.h" +#include "brave/components/brave_ads/core/browser/service/virtual_pref_provider.h" #include "brave/components/brave_ads/core/mojom/brave_ads.mojom.h" #include "brave/components/brave_ads/core/public/ad_units/inline_content_ad/inline_content_ad_info.h" #include "brave/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_info.h" @@ -58,6 +59,7 @@ #import "brave/ios/browser/api/common/common_operations.h" #include "brave/ios/browser/brave_ads/ads_service_factory_ios.h" #include "brave/ios/browser/brave_ads/ads_service_impl_ios.h" +#include "brave/ios/browser/brave_ads/virtual_pref_provider_delegate_ios.h" #include "build/build_config.h" #include "components/prefs/pref_service.h" #include "ios/chrome/browser/shared/model/application_context/application_context.h" @@ -110,6 +112,7 @@ constexpr NSString* kAdsResourceComponentMetadataVersion = @".v1"; @interface BraveAds () { std::unique_ptr adsClientNotifier; + std::unique_ptr virtualPrefProvider; raw_ptr adsService; nw_path_monitor_t networkMonitor; dispatch_queue_t monitorQueue; @@ -152,6 +155,12 @@ constexpr NSString* kAdsResourceComponentMetadataVersion = @".v1"; [self initObservers]; adsClientNotifier = std::make_unique(); + + ProfileIOS* profile = [self getLastUsedProfile]; + CHECK(profile); + virtualPrefProvider = std::make_unique( + self.localStatePrefService, + std::make_unique(*profile)); } return self; } @@ -163,6 +172,8 @@ constexpr NSString* kAdsResourceComponentMetadataVersion = @".v1"; [self stopNetworkMonitor]; + virtualPrefProvider.reset(); + [self deallocAdsClientNotifier]; [self cleanupAdsService]; @@ -1435,7 +1446,11 @@ constexpr NSString* kAdsResourceComponentMetadataVersion = @".v1"; } - (base::Value::Dict)getVirtualPrefs { - return {}; + if (virtualPrefProvider == nullptr) { + return {}; + } + + return virtualPrefProvider->GetPrefs(); } - (void)log:(const char*)file diff --git a/ios/browser/brave_ads/BUILD.gn b/ios/browser/brave_ads/BUILD.gn index 8b5ee0b6799..31542d8117a 100644 --- a/ios/browser/brave_ads/BUILD.gn +++ b/ios/browser/brave_ads/BUILD.gn @@ -9,13 +9,19 @@ source_set("brave_ads") { "ads_service_factory_ios.mm", "ads_service_impl_ios.h", "ads_service_impl_ios.mm", + "virtual_pref_provider_delegate_ios.h", + "virtual_pref_provider_delegate_ios.mm", ] deps = [ + "//base/version_info", "//components/pref_registry", "//components/prefs", + "//components/search_engines", + "//ios/chrome/browser/search_engines/model", "//ios/chrome/browser/shared/model/profile", "//ios/chrome/browser/shared/model/profile:profile_keyed_service_factory", + "//ios/chrome/common", "//ios/web/public", "//sql", ] diff --git a/ios/browser/brave_ads/virtual_pref_provider_delegate_ios.h b/ios/browser/brave_ads/virtual_pref_provider_delegate_ios.h new file mode 100644 index 00000000000..f30f00bd5e1 --- /dev/null +++ b/ios/browser/brave_ads/virtual_pref_provider_delegate_ios.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_IOS_BROWSER_BRAVE_ADS_VIRTUAL_PREF_PROVIDER_DELEGATE_IOS_H_ +#define BRAVE_IOS_BROWSER_BRAVE_ADS_VIRTUAL_PREF_PROVIDER_DELEGATE_IOS_H_ + +#include + +#include "base/memory/raw_ref.h" +#include "brave/components/brave_ads/core/browser/service/virtual_pref_provider.h" + +class ProfileIOS; + +namespace brave_ads { + +class VirtualPrefProviderDelegateIOS : public VirtualPrefProvider::Delegate { + public: + explicit VirtualPrefProviderDelegateIOS(ProfileIOS& profile); + + VirtualPrefProviderDelegateIOS(const VirtualPrefProviderDelegateIOS&) = + delete; + VirtualPrefProviderDelegateIOS& operator=( + const VirtualPrefProviderDelegateIOS&) = delete; + + ~VirtualPrefProviderDelegateIOS() override; + + std::string GetChannel() const override; + + std::string GetDefaultSearchEngineName() const override; + + private: + const raw_ref profile_; +}; + +} // namespace brave_ads + +#endif // BRAVE_IOS_BROWSER_BRAVE_ADS_VIRTUAL_PREF_PROVIDER_DELEGATE_IOS_H_ diff --git a/ios/browser/brave_ads/virtual_pref_provider_delegate_ios.mm b/ios/browser/brave_ads/virtual_pref_provider_delegate_ios.mm new file mode 100644 index 00000000000..9009adcbf63 --- /dev/null +++ b/ios/browser/brave_ads/virtual_pref_provider_delegate_ios.mm @@ -0,0 +1,38 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/ios/browser/brave_ads/virtual_pref_provider_delegate_ios.h" + +#include "base/strings/utf_string_conversions.h" +#include "base/version_info/channel.h" +#include "components/search_engines/template_url_data.h" +#include "components/search_engines/template_url_prepopulate_data.h" +#include "components/search_engines/template_url_prepopulate_data_resolver.h" +#include "ios/chrome/browser/search_engines/model/template_url_prepopulate_data_resolver_factory.h" +#include "ios/chrome/browser/shared/model/profile/profile_ios.h" +#include "ios/chrome/common/channel_info.h" + +namespace brave_ads { + +VirtualPrefProviderDelegateIOS::VirtualPrefProviderDelegateIOS( + ProfileIOS& profile) + : profile_(profile) {} + +VirtualPrefProviderDelegateIOS::~VirtualPrefProviderDelegateIOS() = default; + +std::string VirtualPrefProviderDelegateIOS::GetChannel() const { + return std::string(version_info::GetChannelString(::GetChannel())); +} + +std::string VirtualPrefProviderDelegateIOS::GetDefaultSearchEngineName() const { + auto* prepopulate_data_resolver = + ios::TemplateURLPrepopulateDataResolverFactory::GetForProfile(&*profile_); + const auto template_url_data = prepopulate_data_resolver->GetFallbackSearch(); + const std::u16string& default_search_engine_name = + template_url_data ? template_url_data->short_name() : u""; + return base::UTF16ToUTF8(default_search_engine_name); +} + +} // namespace brave_ads