diff --git a/browser/extensions/api/brave_rewards_api.cc b/browser/extensions/api/brave_rewards_api.cc index b7b70042c726..3d2c654de4e4 100644 --- a/browser/extensions/api/brave_rewards_api.cc +++ b/browser/extensions/api/brave_rewards_api.cc @@ -455,5 +455,41 @@ void BraveRewardsRefreshPublisherFunction::OnRefreshPublisher( std::make_unique(publisher_key))); } +BraveRewardsGetAllNotificationsFunction:: +~BraveRewardsGetAllNotificationsFunction() { +} + +ExtensionFunction::ResponseAction +BraveRewardsGetAllNotificationsFunction::Run() { + Profile* profile = Profile::FromBrowserContext(browser_context()); + RewardsService* rewards_service = + RewardsServiceFactory::GetForProfile(profile); + + auto list = std::make_unique(); + + if (!rewards_service) { + return RespondNow(OneArgument(std::move(list))); + } + + auto notifications = rewards_service->GetAllNotifications(); + + for (auto const& notification : notifications) { + auto item = std::make_unique(); + item->SetString("id", notification.second.id_); + item->SetInteger("type", notification.second.type_); + item->SetInteger("timestamp", notification.second.timestamp_); + + auto args = std::make_unique(); + for (auto const& arg : notification.second.args_) { + args->AppendString(arg); + } + + item->SetList("args", std::move(args)); + list->Append(std::move(item)); + } + + return RespondNow(OneArgument(std::move(list))); +} + } // namespace api } // namespace extensions diff --git a/browser/extensions/api/brave_rewards_api.h b/browser/extensions/api/brave_rewards_api.h index bfb415190746..3e4dea179584 100644 --- a/browser/extensions/api/brave_rewards_api.h +++ b/browser/extensions/api/brave_rewards_api.h @@ -236,6 +236,17 @@ class BraveRewardsRefreshPublisherFunction : public UIThreadExtensionFunction { void OnRefreshPublisher(bool verified, const std::string& publisher_key); }; +class BraveRewardsGetAllNotificationsFunction : + public UIThreadExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("braveRewards.getAllNotifications", UNKNOWN) + + protected: + ~BraveRewardsGetAllNotificationsFunction() override; + + ResponseAction Run() override; +}; + } // namespace api } // namespace extensions diff --git a/browser/ui/webui/brave_webui_source.cc b/browser/ui/webui/brave_webui_source.cc index 4160d2abc6e4..1d3c3490f5fc 100644 --- a/browser/ui/webui/brave_webui_source.cc +++ b/browser/ui/webui/brave_webui_source.cc @@ -274,6 +274,8 @@ void CustomizeWebUIHTMLSource(const std::string &name, { "amount", IDS_BRAVE_UI_AMOUNT }, { "backup", IDS_BRAVE_UI_BACKUP }, { "braveAdsDesc", IDS_BRAVE_UI_BRAVE_ADS_DESC }, + { "braveAdsLaunchMsg", IDS_BRAVE_UI_BRAVE_ADS_LAUNCH_MSG }, + { "braveAdsLaunchTitle", IDS_BRAVE_UI_BRAVE_ADS_LAUNCH_TITLE }, { "braveAdsTitle", IDS_BRAVE_UI_BRAVE_ADS_TITLE }, { "braveContributeDesc", IDS_BRAVE_UI_BRAVE_CONTRIBUTE_DESC }, { "braveContributeTitle", IDS_BRAVE_UI_BRAVE_CONTRIBUTE_TITLE }, @@ -426,6 +428,7 @@ void CustomizeWebUIHTMLSource(const std::string &name, { "tokens", IDS_BRAVE_UI_TOKENS }, { "total", IDS_BRAVE_UI_TOTAL }, { "transactions", IDS_BRAVE_UI_TRANSACTIONS }, + { "turnOnAds", IDS_BRAVE_UI_TURN_ON_ADS }, { "turnOnRewardsDesc", IDS_BRAVE_UI_TURN_ON_REWARDS_DESC }, { "turnOnRewardsTitle", IDS_BRAVE_UI_TURN_ON_REWARDS_TITLE }, { "type", IDS_BRAVE_UI_TYPE }, diff --git a/common/extensions/api/brave_rewards.json b/common/extensions/api/brave_rewards.json index 4cebb043abf5..fa8ba0f0bb90 100644 --- a/common/extensions/api/brave_rewards.json +++ b/common/extensions/api/brave_rewards.json @@ -605,6 +605,47 @@ ] } ] + }, + { + "name": "getAllNotifications", + "type": "function", + "description": "Gets all notifications", + "parameters": [ + { + "type": "function", + "name": "callback", + "parameters": [ + { + "name": "list", + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "notification id" + }, + "type": { + "type": "integer", + "description": "notification type" + }, + "timestamp": { + "type": "integer", + "description": "timestamp when notification was created" + }, + "args": { + "type": "array", + "description": "notification arguments, additional data", + "items": { + "type": "string" + } + } + } + } + } + ] + } + ] } ] } diff --git a/components/brave_ads/browser/BUILD.gn b/components/brave_ads/browser/BUILD.gn index 1bcefe836603..0e4fb6a29baa 100644 --- a/components/brave_ads/browser/BUILD.gn +++ b/components/brave_ads/browser/BUILD.gn @@ -1,4 +1,6 @@ +import("//brave/build/config.gni") import("//brave/components/brave_ads/browser/buildflags/buildflags.gni") +import("//brave/components/brave_rewards/browser/buildflags/buildflags.gni") source_set("browser") { public_deps = [ @@ -80,3 +82,40 @@ source_set("browser") { } } } + +source_set("testutil") { + testonly = true + + deps = [ + ":browser", + "//base", + "//content/public/browser", + "//chrome/test:test_support", + "//testing/gtest", + ] + + if (brave_rewards_enabled) { + deps += [ + "//brave/vendor/bat-native-ledger", + ] + + configs += [ + "//brave/vendor/bat-native-ledger:internal_config" + ] + } + + if (brave_ads_enabled) { + deps += [ + "//brave/vendor/bat-native-ads", + ] + + configs += [ + "//brave/vendor/bat-native-ads:internal_config" + ] + } + + sources = [ + "test_util.cc", + "test_util.h", + ] +} diff --git a/components/brave_ads/browser/ads_service_factory.cc b/components/brave_ads/browser/ads_service_factory.cc index abd26e4bfe68..485a0c7d9c2b 100644 --- a/components/brave_ads/browser/ads_service_factory.cc +++ b/components/brave_ads/browser/ads_service_factory.cc @@ -3,8 +3,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include + #include "brave/components/brave_ads/browser/ads_service_factory.h" +#include "base/time/time.h" #include "brave/components/brave_ads/browser/buildflags/buildflags.h" #include "brave/components/brave_ads/browser/ads_service.h" #include "brave/components/brave_ads/common/pref_names.h" @@ -75,7 +78,7 @@ content::BrowserContext* AdsServiceFactory::GetBrowserContextToUse( } bool AdsServiceFactory::ServiceIsNULLWhileTesting() const { - return true; + return false; } void AdsServiceFactory::RegisterProfilePrefs( @@ -103,6 +106,14 @@ void AdsServiceFactory::RegisterProfilePrefs( #endif registry->RegisterIntegerPref(prefs::kBraveAdsIdleThreshold, 15); + registry->RegisterBooleanPref( + prefs::kBraveAdShouldShowFirstLaunchNotification, + true); + + auto now = static_cast( + (base::Time::Now() - base::Time()).InSeconds()); + registry->RegisterUint64Pref( + prefs::kBraveAdsLaunchNotificationTimestamp, now); if (should_migrate_prefs_from_62) { registry->RegisterBooleanPref(prefs::kBraveAdsPrefsMigratedFrom62, true); diff --git a/components/brave_ads/browser/ads_service_factory.h b/components/brave_ads/browser/ads_service_factory.h index 902292e1d4a5..998a61033af1 100644 --- a/components/brave_ads/browser/ads_service_factory.h +++ b/components/brave_ads/browser/ads_service_factory.h @@ -3,8 +3,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef BRAVE_COMPONENTS_BRAVE_ADS_ADS_SERVICE_FACTORY_H_ -#define BRAVE_COMPONENTS_BRAVE_ADS_ADS_SERVICE_FACTORY_H_ +#ifndef BRAVE_COMPONENTS_BRAVE_ADS_BROWSER_ADS_SERVICE_FACTORY_H_ +#define BRAVE_COMPONENTS_BRAVE_ADS_BROWSER_ADS_SERVICE_FACTORY_H_ #include "base/memory/singleton.h" #include "components/keyed_service/content/browser_context_keyed_service_factory.h" @@ -21,6 +21,9 @@ class AdsServiceFactory : public BrowserContextKeyedServiceFactory { static AdsServiceFactory* GetInstance(); + void RegisterProfilePrefs( + user_prefs::PrefRegistrySyncable* registry) override; + private: friend struct base::DefaultSingletonTraits; @@ -33,8 +36,6 @@ class AdsServiceFactory : public BrowserContextKeyedServiceFactory { content::BrowserContext* GetBrowserContextToUse( content::BrowserContext* context) const override; bool ServiceIsNULLWhileTesting() const override; - void RegisterProfilePrefs( - user_prefs::PrefRegistrySyncable* registry) override; bool ShouldMigratePrefs(user_prefs::PrefRegistrySyncable* registry) const; bool ShouldMigratePrefsFrom62( user_prefs::PrefRegistrySyncable* registry) const; @@ -44,4 +45,4 @@ class AdsServiceFactory : public BrowserContextKeyedServiceFactory { } // namespace brave_ads -#endif // BRAVE_COMPONENTS_BRAVE_ADS_ADS_SERVICE_FACTORY_H_ +#endif // BRAVE_COMPONENTS_BRAVE_ADS_BROWSER_ADS_SERVICE_FACTORY_H_ diff --git a/components/brave_ads/browser/ads_service_impl.cc b/components/brave_ads/browser/ads_service_impl.cc index 64e2d9541e70..fd680223372a 100644 --- a/components/brave_ads/browser/ads_service_impl.cc +++ b/components/brave_ads/browser/ads_service_impl.cc @@ -30,6 +30,7 @@ #include "brave/components/brave_ads/common/switches.h" #include "brave/components/brave_rewards/browser/rewards_service.h" #include "brave/components/brave_rewards/browser/rewards_service_factory.h" +#include "brave/components/brave_rewards/browser/rewards_notification_service.h" #include "brave/components/services/bat_ads/public/cpp/ads_client_mojo_bridge.h" #include "brave/components/services/bat_ads/public/interfaces/bat_ads.mojom.h" #include "chrome/browser/browser_process.h" @@ -60,8 +61,17 @@ #include "net/android/network_library.h" #endif +using brave_rewards::RewardsNotificationService; + namespace brave_ads { +namespace { + +const char kRewardsNotificationAdsLaunch[] = + "rewards_notification_ads_launch"; + +} + class LogStreamImpl : public ads::LogStream { public: LogStreamImpl(const char* file, @@ -258,6 +268,7 @@ AdsServiceImpl::AdsServiceImpl(Profile* profile) base::TaskShutdownBehavior::BLOCK_SHUTDOWN})), base_path_(profile_->GetPath().AppendASCII("ads_service")), next_timer_id_(0), + ads_launch_id_(0), is_supported_region_(false), bundle_state_backend_( new BundleStateDatabase(base_path_.AppendASCII("bundle_state"))), @@ -273,6 +284,7 @@ AdsServiceImpl::AdsServiceImpl(Profile* profile) file_task_runner_->PostTask(FROM_HERE, base::BindOnce(&EnsureBaseDirectoryExists, base_path_)); + profile_pref_change_registrar_.Init(profile_->GetPrefs()); profile_pref_change_registrar_.Add( prefs::kBraveAdsEnabled, @@ -340,6 +352,8 @@ void AdsServiceImpl::OnMaybeStartForRegion( return; } + MaybeShowFirstLaunchNotification(); + if (IsAdsEnabled()) { if (should_restart) { base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, @@ -412,6 +426,131 @@ void AdsServiceImpl::Start() { base::BindOnce(&AdsServiceImpl::OnCreate, AsWeakPtr())); } +void AdsServiceImpl::MaybeShowFirstLaunchNotification() { + auto ads_enabled = profile_->GetPrefs()->GetBoolean( + prefs::kBraveAdsEnabled); + auto prefs_migrated_from_62 = profile_->GetPrefs()->GetBoolean( + prefs::kBraveAdsPrefsMigratedFrom62); + + if (!ads_enabled || + !prefs_migrated_from_62 || + !ShouldShowFirstLaunchNotification() || + !profile_->GetPrefs()->GetBoolean( + brave_rewards::prefs::kBraveRewardsEnabled)) { + StartFirstLaunchNotificationTimer(); + return; + } + + auto now = static_cast( + (base::Time::Now() - base::Time()).InSeconds()); + profile_->GetPrefs()->SetUint64( + prefs::kBraveAdsLaunchNotificationTimestamp, now); + + ShowFirstLaunchNotification(); + + StartFirstLaunchNotificationTimer(); +} + +bool AdsServiceImpl::ShouldShowFirstLaunchNotification() { + return profile_->GetPrefs()->GetBoolean( + prefs::kBraveAdShouldShowFirstLaunchNotification); +} + +void AdsServiceImpl::RemoveFirstLaunchNotification() { + KillTimer(ads_launch_id_); + + auto* rewards_service = + brave_rewards::RewardsServiceFactory::GetForProfile(profile_); + auto* rewards_notification_service = + rewards_service->GetNotificationService(); + rewards_notification_service->DeleteNotification( + kRewardsNotificationAdsLaunch); +} + +void AdsServiceImpl::ShowFirstLaunchNotification() { + auto* rewards_service = + brave_rewards::RewardsServiceFactory::GetForProfile(profile_); + + auto* rewards_notification_service = + rewards_service->GetNotificationService(); + + RewardsNotificationService::RewardsNotificationArgs args; + rewards_notification_service->AddNotification( + RewardsNotificationService::REWARDS_NOTIFICATION_ADS_LAUNCH, + args, kRewardsNotificationAdsLaunch); + + profile_->GetPrefs()->SetBoolean( + prefs::kBraveAdShouldShowFirstLaunchNotification, false); +} + +void AdsServiceImpl::StartFirstLaunchNotificationTimer() { + uint64_t timer_offset_in_seconds; + + if (HasFirstLaunchNotificationExpired()) { + timer_offset_in_seconds = base::Time::kSecondsPerMinute; + } else { + timer_offset_in_seconds = GetFirstLaunchNotificationTimerOffset(); + } + + auto timer_offset = base::TimeDelta::FromSeconds(timer_offset_in_seconds); + + uint32_t timer_id = next_timer_id(); + ads_launch_id_ = timer_id; + timers_[timer_id] = std::make_unique(); + timers_[timer_id]->Start(FROM_HERE, + timer_offset, + base::BindOnce(&AdsServiceImpl::OnFirstLaunchNotificationTimedOut, + AsWeakPtr(), + timer_id)); +} + +uint64_t AdsServiceImpl::GetFirstLaunchNotificationTimeout() { + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + auto timeout_in_seconds = + command_line.HasSwitch(switches::kDebug) + ? (5 * base::Time::kSecondsPerMinute) + : (base::Time::kMicrosecondsPerWeek / + base::Time::kMicrosecondsPerSecond); + return timeout_in_seconds; +} + +uint64_t AdsServiceImpl::GetFirstLaunchNotificationTimerOffset() { + auto timeout_in_seconds = GetFirstLaunchNotificationTimeout(); + + auto timestamp_in_seconds = profile_->GetPrefs()->GetUint64( + prefs::kBraveAdsLaunchNotificationTimestamp); + + auto now_in_seconds = static_cast( + (base::Time::Now() - base::Time()).InSeconds()); + + auto timer_offset = (timestamp_in_seconds + + timeout_in_seconds) - now_in_seconds; + + return timer_offset; +} + +bool AdsServiceImpl::HasFirstLaunchNotificationExpired() { + auto timeout_in_seconds = GetFirstLaunchNotificationTimeout(); + + auto timestamp_in_seconds = profile_->GetPrefs()->GetUint64( + prefs::kBraveAdsLaunchNotificationTimestamp); + + auto now_in_seconds = static_cast( + (base::Time::Now() - base::Time()).InSeconds()); + + if (now_in_seconds < (timestamp_in_seconds + timeout_in_seconds)) { + return false; + } + + return true; +} + +void AdsServiceImpl::OnFirstLaunchNotificationTimedOut(uint32_t timer_id) { + timers_.erase(timer_id); + RemoveFirstLaunchNotification(); +} + void AdsServiceImpl::Stop() { if (connected()) { // this is kind of weird, but we need to call Initialize on disable too @@ -610,7 +749,10 @@ void AdsServiceImpl::SetAdsEnabled(const bool is_enabled) { if (is_enabled) { profile_->GetPrefs()->SetBoolean( prefs::kBraveAdsPrefsMigratedFrom62, false); + + RemoveFirstLaunchNotification(); } + profile_->GetPrefs()->SetBoolean(prefs::kBraveAdsEnabled, is_enabled); } diff --git a/components/brave_ads/browser/ads_service_impl.h b/components/brave_ads/browser/ads_service_impl.h index ac4acd126c6f..dbaf2398791e 100644 --- a/components/brave_ads/browser/ads_service_impl.h +++ b/components/brave_ads/browser/ads_service_impl.h @@ -19,6 +19,7 @@ #include "brave/components/brave_ads/browser/ads_service.h" #include "brave/components/brave_ads/browser/background_helper.h" #include "brave/components/services/bat_ads/public/interfaces/bat_ads.mojom.h" +#include "brave/components/brave_rewards/browser/rewards_notification_service_observer.h" #include "chrome/browser/notifications/notification_handler.h" #include "components/history/core/browser/history_service_observer.h" #include "components/prefs/pref_change_registrar.h" @@ -29,6 +30,8 @@ #include "ui/base/idle/idle.h" #endif +using brave_rewards::RewardsNotificationService; + class NotificationDisplayService; class Profile; @@ -171,6 +174,7 @@ class AdsServiceImpl : public AdsService, const ads::OnGetAdsCallback& callback, const std::string& category, const std::vector& ads); + void OnSaveBundleState(const ads::OnSaveCallback& callback, bool success); void OnLoaded( const ads::OnLoadCallback& callback, @@ -195,6 +199,15 @@ class AdsServiceImpl : public AdsService, void NotificationTimedOut( uint32_t timer_id, const std::string& notification_id); + void MaybeShowFirstLaunchNotification(); + bool ShouldShowFirstLaunchNotification(); + void RemoveFirstLaunchNotification(); + void ShowFirstLaunchNotification(); + void StartFirstLaunchNotificationTimer(); + uint64_t GetFirstLaunchNotificationTimeout(); + uint64_t GetFirstLaunchNotificationTimerOffset(); + bool HasFirstLaunchNotificationExpired(); + void OnFirstLaunchNotificationTimedOut(uint32_t timer_id); uint32_t next_timer_id(); @@ -206,6 +219,7 @@ class AdsServiceImpl : public AdsService, const base::FilePath base_path_; std::map> timers_; uint32_t next_timer_id_; + uint32_t ads_launch_id_; bool is_supported_region_; std::unique_ptr bundle_state_backend_; NotificationDisplayService* display_service_; // NOT OWNED diff --git a/components/brave_ads/browser/ads_service_impl_unittest.cc b/components/brave_ads/browser/ads_service_impl_unittest.cc new file mode 100644 index 000000000000..cbd334d0e95a --- /dev/null +++ b/components/brave_ads/browser/ads_service_impl_unittest.cc @@ -0,0 +1,183 @@ +/* Copyright (c) 2019 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 http://mozilla.org/MPL/2.0/. */ + +#include + +#include "base/files/scoped_temp_dir.h" +#include "extensions/browser/test_event_router.h" +#include "brave/components/brave_ads/browser/ads_service.h" +#include "brave/components/brave_ads/browser/ads_service_factory.h" +#include "brave/components/brave_rewards/browser/rewards_service_factory.h" +#include "brave/components/brave_rewards/browser/rewards_service.h" +#include "brave/components/brave_ads/browser/test_util.h" +#include "chrome/browser/profiles/profile.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "brave/components/brave_rewards/common/pref_names.h" +#include "components/prefs/pref_service.h" + +// npm run test -- brave_unit_tests --filter=AdsServiceTest.* + +using brave_rewards::RewardsService; +using brave_rewards::RewardsServiceFactory; +using brave_ads::AdsService; +using brave_ads::AdsServiceFactory; + +using ::testing::_; + +class MockRewardsService : public RewardsService { + public: + MockRewardsService() {} + ~MockRewardsService() {} + + MOCK_METHOD0(CreateWallet, void()); + MOCK_METHOD0(FetchWalletProperties, void()); + MOCK_METHOD7(GetContentSiteList, + void(uint32_t, + uint32_t, + uint64_t, + uint64_t, + bool, + uint32_t, + const brave_rewards::GetContentSiteListCallback&)); + MOCK_METHOD2(FetchGrants, void(const std::string&, const std::string&)); + MOCK_METHOD2(GetGrantCaptcha, void(const std::string&, const std::string&)); + MOCK_CONST_METHOD2(SolveGrantCaptcha, void(const std::string&, + const std::string&)); + MOCK_METHOD1(GetWalletPassphrase, + void(const brave_rewards::GetWalletPassphraseCallback&)); + MOCK_METHOD1(GetExcludedPublishersNumber, + void(const brave_rewards::GetExcludedPublishersNumberCallback&)); + MOCK_CONST_METHOD1(RecoverWallet, void(const std::string)); + MOCK_CONST_METHOD1(ExcludePublisher, void(const std::string)); + MOCK_METHOD0(RestorePublishers, void()); + MOCK_METHOD2(OnLoad, void(SessionID, const GURL&)); + MOCK_METHOD1(OnUnload, void(SessionID)); + MOCK_METHOD1(OnShow, void(SessionID)); + MOCK_METHOD1(OnHide, void(SessionID)); + MOCK_METHOD1(OnForeground, void(SessionID)); + MOCK_METHOD1(OnBackground, void(SessionID)); + MOCK_METHOD1(OnMediaStart, void(SessionID)); + MOCK_METHOD1(OnMediaStop, void(SessionID)); + MOCK_METHOD4(OnXHRLoad, void(SessionID, + const GURL&, + const GURL&, + const GURL&)); + MOCK_METHOD5(OnPostData, void(SessionID, + const GURL&, + const GURL&, + const GURL&, + const std::string&)); + MOCK_METHOD1(GetReconcileStamp, + void(const brave_rewards::GetReconcileStampCallback&)); + MOCK_METHOD1(GetAddresses, + void(const brave_rewards::GetAddressesCallback&)); + MOCK_METHOD1(SetRewardsMainEnabled, void(bool)); + MOCK_METHOD1(GetPublisherMinVisitTime, + void(const brave_rewards::GetPublisherMinVisitTimeCallback&)); + MOCK_CONST_METHOD1(SetPublisherMinVisitTime, void(uint64_t)); + MOCK_METHOD1(GetPublisherMinVisits, + void(const brave_rewards::GetPublisherMinVisitsCallback&)); + MOCK_CONST_METHOD1(SetPublisherMinVisits, void(unsigned int)); + MOCK_METHOD1(GetPublisherAllowNonVerified, + void(const brave_rewards::GetPublisherAllowNonVerifiedCallback&)); + MOCK_CONST_METHOD1(SetPublisherAllowNonVerified, void(bool)); + MOCK_METHOD1(GetPublisherAllowVideos, + void(const brave_rewards::GetPublisherAllowVideosCallback&)); + MOCK_CONST_METHOD1(SetPublisherAllowVideos, void(bool)); + MOCK_CONST_METHOD1(SetContributionAmount, void(double)); + MOCK_CONST_METHOD0(SetUserChangedContribution, void()); + MOCK_METHOD1(GetAutoContribute, + void(brave_rewards::GetAutoContributeCallback)); + MOCK_CONST_METHOD1(SetAutoContribute, void(bool)); + MOCK_METHOD2(SetTimer, void(uint64_t, uint32_t*)); + MOCK_METHOD1(GetAllBalanceReports, + void(const brave_rewards::GetAllBalanceReportsCallback&)); + MOCK_METHOD0(GetCurrentBalanceReport, void()); + MOCK_METHOD1(IsWalletCreated, + void(const brave_rewards::IsWalletCreatedCallback&)); + MOCK_METHOD4(GetPublisherActivityFromUrl, void(uint64_t, + const std::string&, + const std::string&, + const std::string&)); + MOCK_METHOD1(GetContributionAmount, + void(const brave_rewards::GetContributionAmountCallback&)); + MOCK_METHOD2(GetPublisherBanner, + void(const std::string&, + brave_rewards::GetPublisherBannerCallback)); + MOCK_METHOD4(OnDonate, void(const std::string&, + int, + bool, + const ledger::PublisherInfo*)); + MOCK_METHOD4(OnDonate, void(const std::string&, + int, + bool, + std::unique_ptr)); + MOCK_METHOD1(RemoveRecurringTip, void(const std::string&)); + MOCK_METHOD1(GetRecurringTipsUI, + void(brave_rewards::GetRecurringTipsCallback)); + MOCK_METHOD1(GetOneTimeTipsUI, void(brave_rewards::GetOneTimeTipsCallback)); + MOCK_METHOD2(SetContributionAutoInclude, void(const std::string&, bool)); + MOCK_CONST_METHOD0(GetNotificationService, + brave_rewards::RewardsNotificationService*()); + MOCK_METHOD0(CheckImported, bool()); + MOCK_METHOD0(SetBackupCompleted, void()); + MOCK_METHOD1(GetAutoContributeProps, + void(const brave_rewards::GetAutoContributePropsCallback&)); + MOCK_METHOD1(GetPendingContributionsTotal, + void(const brave_rewards::GetPendingContributionsTotalCallback&)); + MOCK_CONST_METHOD1(GetRewardsMainEnabled, + void(const brave_rewards::GetRewardsMainEnabledCallback&)); + MOCK_METHOD1(SetCatalogIssuers, void(const std::string&)); + MOCK_METHOD1(ConfirmAd, void(const std::string&)); + MOCK_METHOD1(GetRewardsInternalsInfo, + void(brave_rewards::GetRewardsInternalsInfoCallback)); + MOCK_METHOD1(GetAddressesForPaymentId, + void(const brave_rewards::GetAddressesCallback&)); + MOCK_METHOD1(GetTransactionHistoryForThisCycle, + void(brave_rewards::GetTransactionHistoryForThisCycleCallback)); + MOCK_METHOD2(SaveRecurringTip, void(const std::string&, const int)); + MOCK_METHOD2(RefreshPublisher, void(const std::string&, + brave_rewards::RefreshPublisherCallback)); + MOCK_METHOD0(GetAllNotifications, + const brave_rewards::RewardsNotificationService::RewardsNotificationsMap&()); +}; + +class AdsServiceTest : public testing::Test { + public: + AdsServiceTest() {} + ~AdsServiceTest() override {} + + AdsService* ads_service_; + + protected: + void SetUp() override { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + profile_ = brave_ads::CreateBraveAdsProfile(temp_dir_.GetPath()); + ASSERT_TRUE(profile_.get() != NULL); + RewardsServiceFactory::SetServiceForTesting(new MockRewardsService()); + rewards_service_ = static_cast( + RewardsServiceFactory::GetForProfile(profile())); + ads_service_ = AdsServiceFactory::GetForProfile(profile()); + ASSERT_TRUE(AdsServiceFactory::GetInstance() != NULL); + ASSERT_TRUE(ads_service() != NULL); + } + + void TearDown() override { + profile_.reset(); + delete rewards_service_; + } + + Profile* profile() { return profile_.get(); } + AdsService* ads_service() { return ads_service_; } + MockRewardsService* rewards_service() { return rewards_service_; } + + private: + content::TestBrowserThreadBundle thread_bundle_; + std::unique_ptr profile_; + base::ScopedTempDir temp_dir_; + MockRewardsService* rewards_service_; +}; diff --git a/components/brave_ads/browser/test_util.cc b/components/brave_ads/browser/test_util.cc new file mode 100644 index 000000000000..c9eb64ff090b --- /dev/null +++ b/components/brave_ads/browser/test_util.cc @@ -0,0 +1,39 @@ +/* Copyright (c) 2019 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 http://mozilla.org/MPL/2.0/. */ + +#include + +#include "brave/components/brave_ads/browser/test_util.h" + +#include "base/files/file_util.h" +#include "base/strings/utf_string_conversions.h" +#include "brave/components/brave_rewards/browser/rewards_service.h" +#include "brave/components/brave_ads/browser/ads_service.h" +#include "brave/components/brave_ads/browser/ads_service_factory.h" +#include "chrome/browser/bitmap_fetcher/bitmap_fetcher_service_factory.h" +#include "chrome/browser/prefs/browser_prefs.h" +#include "chrome/test/base/testing_profile.h" +#include "chrome/test/base/testing_profile_manager.h" +#include "components/sync_preferences/pref_service_mock_factory.h" +#include "components/sync_preferences/testing_pref_service_syncable.h" + +namespace brave_ads { + +std::unique_ptr CreateBraveAdsProfile(const base::FilePath& path) { + BitmapFetcherServiceFactory::GetInstance(); + AdsServiceFactory::GetInstance(); + sync_preferences::PrefServiceMockFactory factory; + auto registry = base::MakeRefCounted(); + std::unique_ptr prefs( + factory.CreateSyncable(registry.get())); + brave_rewards::RewardsService::RegisterProfilePrefs(registry.get()); + RegisterUserProfilePrefs(registry.get()); + TestingProfile::Builder profile_builder; + profile_builder.SetPrefService(std::move(prefs)); + profile_builder.SetPath(path); + return profile_builder.Build(); +} + +} // namespace brave_ads diff --git a/components/brave_ads/browser/test_util.h b/components/brave_ads/browser/test_util.h new file mode 100644 index 000000000000..768466e61f0e --- /dev/null +++ b/components/brave_ads/browser/test_util.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2019 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 http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_BRAVE_ADS_BROWSER_TEST_UTIL_H_ +#define BRAVE_COMPONENTS_BRAVE_ADS_BROWSER_TEST_UTIL_H_ + +#include + +#include "base/files/file_path.h" + +class KeyedService; +class Profile; + +namespace brave_ads { + +std::unique_ptr CreateBraveAdsProfile(const base::FilePath& path); + +} // namespace brave_ads + +#endif // BRAVE_COMPONENTS_BRAVE_ADS_BROWSER_TEST_UTIL_H_ diff --git a/components/brave_ads/common/pref_names.cc b/components/brave_ads/common/pref_names.cc index 78c71fc52501..9dec331170c6 100644 --- a/components/brave_ads/common/pref_names.cc +++ b/components/brave_ads/common/pref_names.cc @@ -15,6 +15,11 @@ const char kBraveAdsPerHour[] = "brave.brave_ads.ads_per_hour"; const char kBraveAdsPerDay[] = "brave.brave_ads.ads_per_day"; const char kBraveAdsIdleThreshold[] = "brave.brave_ads.idle_threshold"; +const char kBraveAdShouldShowFirstLaunchNotification[] = + "brave.brave_ads.should_show_first_launch_notification"; +const char kBraveAdsLaunchNotificationTimestamp[] = + "brave.brave_ads.launch_notification_timestamp"; + const int kBraveAdsPrefsDefaultVersion = 1; const int kBraveAdsPrefsCurrentVersion = 2; const char kBraveAdsPrefsVersion[] = "brave.brave_ads.prefs.version"; diff --git a/components/brave_ads/common/pref_names.h b/components/brave_ads/common/pref_names.h index be25ef55c5af..893d5a8a0767 100644 --- a/components/brave_ads/common/pref_names.h +++ b/components/brave_ads/common/pref_names.h @@ -11,11 +11,13 @@ namespace brave_ads { namespace prefs { extern const char kBraveAdsEnabled[]; - extern const char kBraveAdsPerHour[]; extern const char kBraveAdsPerDay[]; extern const char kBraveAdsIdleThreshold[]; +extern const char kBraveAdShouldShowFirstLaunchNotification[]; +extern const char kBraveAdsLaunchNotificationTimestamp[]; + extern const int kBraveAdsPrefsDefaultVersion; extern const int kBraveAdsPrefsCurrentVersion; extern const char kBraveAdsPrefsVersion[]; diff --git a/components/brave_rewards/browser/extension_rewards_notification_service_observer.cc b/components/brave_rewards/browser/extension_rewards_notification_service_observer.cc index a988c1bea29d..ab679da0ee2e 100644 --- a/components/brave_rewards/browser/extension_rewards_notification_service_observer.cc +++ b/components/brave_rewards/browser/extension_rewards_notification_service_observer.cc @@ -1,7 +1,12 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public +/* Copyright (c) 2019 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 http://mozilla.org/MPL/2.0/. */ +#include +#include +#include + #include "brave/components/brave_rewards/browser/extension_rewards_notification_service_observer.h" #include "brave/common/extensions/api/rewards_notifications.h" @@ -11,12 +16,12 @@ namespace brave_rewards { ExtensionRewardsNotificationServiceObserver:: - ExtensionRewardsNotificationServiceObserver(Profile* profile) +ExtensionRewardsNotificationServiceObserver(Profile* profile) : profile_(profile) { } ExtensionRewardsNotificationServiceObserver:: - ~ExtensionRewardsNotificationServiceObserver() { +~ExtensionRewardsNotificationServiceObserver() { } void ExtensionRewardsNotificationServiceObserver::OnNotificationAdded( @@ -26,17 +31,19 @@ void ExtensionRewardsNotificationServiceObserver::OnNotificationAdded( extensions::EventRouter* event_router = extensions::EventRouter::Get(profile_); if (event_router) { - std::unique_ptr args( - extensions::api::rewards_notifications::OnNotificationAdded::Create( - rewards_notification.id_, rewards_notification.type_, - rewards_notification.timestamp_, rewards_notification.args_) - .release()); - std::unique_ptr event(new extensions::Event( - extensions::events::BRAVE_REWARDS_NOTIFICATION_ADDED, - extensions::api::rewards_notifications::OnNotificationAdded::kEventName, - std::move(args))); - event_router->BroadcastEvent(std::move(event)); + return; } + + std::unique_ptr args( + extensions::api::rewards_notifications::OnNotificationAdded::Create( + rewards_notification.id_, rewards_notification.type_, + rewards_notification.timestamp_, rewards_notification.args_) + .release()); + std::unique_ptr event(new extensions::Event( + extensions::events::BRAVE_REWARDS_NOTIFICATION_ADDED, + extensions::api::rewards_notifications::OnNotificationAdded::kEventName, + std::move(args))); + event_router->BroadcastEvent(std::move(event)); } void ExtensionRewardsNotificationServiceObserver::OnNotificationDeleted( @@ -45,18 +52,20 @@ void ExtensionRewardsNotificationServiceObserver::OnNotificationDeleted( rewards_notification) { extensions::EventRouter* event_router = extensions::EventRouter::Get(profile_); - if (event_router) { - std::unique_ptr args( - extensions::api::rewards_notifications::OnNotificationDeleted::Create( - rewards_notification.id_, rewards_notification.type_, - rewards_notification.timestamp_) - .release()); - std::unique_ptr event(new extensions::Event( - extensions::events::BRAVE_REWARDS_NOTIFICATION_DELETED, - extensions::api::rewards_notifications::OnNotificationDeleted::kEventName, - std::move(args))); - event_router->BroadcastEvent(std::move(event)); + if (!event_router) { + return; } + + std::unique_ptr args( + extensions::api::rewards_notifications::OnNotificationDeleted::Create( + rewards_notification.id_, rewards_notification.type_, + rewards_notification.timestamp_) + .release()); + std::unique_ptr event(new extensions::Event( + extensions::events::BRAVE_REWARDS_NOTIFICATION_DELETED, + extensions::api::rewards_notifications::OnNotificationDeleted::kEventName, + std::move(args))); + event_router->BroadcastEvent(std::move(event)); } void ExtensionRewardsNotificationServiceObserver:: @@ -64,17 +73,19 @@ void ExtensionRewardsNotificationServiceObserver:: RewardsNotificationService* rewards_notification_service) { extensions::EventRouter* event_router = extensions::EventRouter::Get(profile_); - if (event_router) { - std::unique_ptr args( - extensions::api::rewards_notifications::OnAllNotificationsDeleted::Create() - .release()); - std::unique_ptr event(new extensions::Event( - extensions::events::BRAVE_REWARDS_ALL_NOTIFICATIONS_DELETED, - extensions::api::rewards_notifications::OnAllNotificationsDeleted:: - kEventName, - std::move(args))); - event_router->BroadcastEvent(std::move(event)); + if (!event_router) { + return; } + + std::unique_ptr args( + extensions::api::rewards_notifications::OnAllNotificationsDeleted::Create() + .release()); + std::unique_ptr event(new extensions::Event( + extensions::events::BRAVE_REWARDS_ALL_NOTIFICATIONS_DELETED, + extensions::api::rewards_notifications::OnAllNotificationsDeleted:: + kEventName, + std::move(args))); + event_router->BroadcastEvent(std::move(event)); } void ExtensionRewardsNotificationServiceObserver::OnGetNotification( @@ -84,17 +95,19 @@ void ExtensionRewardsNotificationServiceObserver::OnGetNotification( extensions::EventRouter* event_router = extensions::EventRouter::Get(profile_); if (event_router) { - std::unique_ptr args( - extensions::api::rewards_notifications::OnGetNotification::Create( - rewards_notification.id_, rewards_notification.type_, - rewards_notification.timestamp_, rewards_notification.args_) - .release()); - std::unique_ptr event(new extensions::Event( - extensions::events::BRAVE_REWARDS_GET_NOTIFICATION, - extensions::api::rewards_notifications::OnGetNotification::kEventName, - std::move(args))); - event_router->BroadcastEvent(std::move(event)); + return; } + + std::unique_ptr args( + extensions::api::rewards_notifications::OnGetNotification::Create( + rewards_notification.id_, rewards_notification.type_, + rewards_notification.timestamp_, rewards_notification.args_) + .release()); + std::unique_ptr event(new extensions::Event( + extensions::events::BRAVE_REWARDS_GET_NOTIFICATION, + extensions::api::rewards_notifications::OnGetNotification::kEventName, + std::move(args))); + event_router->BroadcastEvent(std::move(event)); } void ExtensionRewardsNotificationServiceObserver::OnGetAllNotifications( @@ -104,29 +117,32 @@ void ExtensionRewardsNotificationServiceObserver::OnGetAllNotifications( extensions::EventRouter* event_router = extensions::EventRouter::Get(profile_); if (event_router) { - std::vector - notifications_list; - for (auto& item : rewards_notifications_list) { - notifications_list.push_back( - extensions::api::rewards_notifications::OnGetAllNotifications:: - NotificationsType()); - auto& notifications_type = notifications_list[notifications_list.size() - 1]; - notifications_type.id = item.id_; - notifications_type.type = item.type_; - notifications_type.timestamp = item.timestamp_; - notifications_type.args = item.args_; - } - std::unique_ptr args( - extensions::api::rewards_notifications::OnGetAllNotifications::Create( - notifications_list) - .release()); - std::unique_ptr event(new extensions::Event( - extensions::events::BRAVE_REWARDS_GET_ALL_NOTIFICATIONS, - extensions::api::rewards_notifications::OnGetAllNotifications::kEventName, - std::move(args))); - event_router->BroadcastEvent(std::move(event)); + return; + } + + std::vector + notifications_list; + for (auto& item : rewards_notifications_list) { + notifications_list.push_back( + extensions::api::rewards_notifications::OnGetAllNotifications:: + NotificationsType()); + auto& notifications_type = + notifications_list[notifications_list.size() - 1]; + notifications_type.id = item.id_; + notifications_type.type = item.type_; + notifications_type.timestamp = item.timestamp_; + notifications_type.args = item.args_; } + std::unique_ptr args( + extensions::api::rewards_notifications::OnGetAllNotifications::Create( + notifications_list) + .release()); + std::unique_ptr event(new extensions::Event( + extensions::events::BRAVE_REWARDS_GET_ALL_NOTIFICATIONS, + extensions::api::rewards_notifications::OnGetAllNotifications::kEventName, + std::move(args))); + event_router->BroadcastEvent(std::move(event)); } } // namespace brave_rewards diff --git a/components/brave_rewards/browser/extension_rewards_notification_service_observer.h b/components/brave_rewards/browser/extension_rewards_notification_service_observer.h index 59566df1ed73..4158cb795e65 100644 --- a/components/brave_rewards/browser/extension_rewards_notification_service_observer.h +++ b/components/brave_rewards/browser/extension_rewards_notification_service_observer.h @@ -1,9 +1,10 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public +/* Copyright (c) 2019 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 http://mozilla.org/MPL/2.0/. */ -#ifndef BRAVE_COMPONENTS_BRAVE_REWARDS_BROWSER_REWARDS_NOTIFICATION_SERVICE_OBSERVER_EXTENSIONS_IMPL_ -#define BRAVE_COMPONENTS_BRAVE_REWARDS_BROWSER_REWARDS_NOTIFICATION_SERVICE_OBSERVER_EXTENSIONS_IMPL_ +#ifndef BRAVE_COMPONENTS_BRAVE_REWARDS_BROWSER_EXTENSION_REWARDS_NOTIFICATION_SERVICE_OBSERVER_H_ +#define BRAVE_COMPONENTS_BRAVE_REWARDS_BROWSER_EXTENSION_REWARDS_NOTIFICATION_SERVICE_OBSERVER_H_ #include "base/macros.h" #include "brave/components/brave_rewards/browser/rewards_notification_service_observer.h" @@ -17,7 +18,7 @@ class RewardsNotificationService; class ExtensionRewardsNotificationServiceObserver : public RewardsNotificationServiceObserver { public: - ExtensionRewardsNotificationServiceObserver(Profile* profile); + explicit ExtensionRewardsNotificationServiceObserver(Profile* profile); ~ExtensionRewardsNotificationServiceObserver() override; // RewardsNotificationServiceObserver implementation @@ -48,4 +49,4 @@ class ExtensionRewardsNotificationServiceObserver } // namespace brave_rewards -#endif // BRAVE_COMPONENTS_BRAVE_REWARDS_BROWSER_REWARDS_NOTIFICATION_SERVICE_OBSERVER_EXTENSIONS_IMPL_ +#endif // BRAVE_COMPONENTS_BRAVE_REWARDS_BROWSER_EXTENSION_REWARDS_NOTIFICATION_SERVICE_OBSERVER_H_ diff --git a/components/brave_rewards/browser/rewards_notification_service.cc b/components/brave_rewards/browser/rewards_notification_service.cc index 3cecd1c937f3..91fd227a94b9 100644 --- a/components/brave_rewards/browser/rewards_notification_service.cc +++ b/components/brave_rewards/browser/rewards_notification_service.cc @@ -1,4 +1,5 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public +/* Copyright (c) 2019 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 http://mozilla.org/MPL/2.0/. */ @@ -16,14 +17,18 @@ RewardsNotificationService::~RewardsNotificationService() { RewardsNotificationService::RewardsNotification::RewardsNotification() {} -RewardsNotificationService::RewardsNotification::RewardsNotification(const RewardsNotificationService::RewardsNotification& prop) = default; +RewardsNotificationService::RewardsNotification::RewardsNotification( + const RewardsNotificationService::RewardsNotification& prop) = default; RewardsNotificationService::RewardsNotification::RewardsNotification( RewardsNotificationService::RewardsNotificationID id, RewardsNotificationService::RewardsNotificationType type, RewardsNotificationService::RewardsNotificationTimestamp timestamp, RewardsNotificationService::RewardsNotificationArgs args) - : id_(id), type_(type), timestamp_(timestamp), args_(args) {} + : id_(id), + type_(type), + timestamp_(timestamp), + args_(args) {} RewardsNotificationService::RewardsNotification::~RewardsNotification() {} diff --git a/components/brave_rewards/browser/rewards_notification_service.h b/components/brave_rewards/browser/rewards_notification_service.h index 12077984601c..ca9e1521d25e 100644 --- a/components/brave_rewards/browser/rewards_notification_service.h +++ b/components/brave_rewards/browser/rewards_notification_service.h @@ -36,7 +36,8 @@ class RewardsNotificationService { REWARDS_NOTIFICATION_IMPENDING_CONTRIBUTION, REWARDS_NOTIFICATION_INSUFFICIENT_FUNDS, REWARDS_NOTIFICATION_BACKUP_WALLET, - REWARDS_NOTIFICATION_TIPS_PROCESSED + REWARDS_NOTIFICATION_TIPS_PROCESSED, + REWARDS_NOTIFICATION_ADS_LAUNCH }; struct RewardsNotification { diff --git a/components/brave_rewards/browser/rewards_notification_service_impl.cc b/components/brave_rewards/browser/rewards_notification_service_impl.cc index 6e09e9393006..ad69562ba950 100644 --- a/components/brave_rewards/browser/rewards_notification_service_impl.cc +++ b/components/brave_rewards/browser/rewards_notification_service_impl.cc @@ -33,7 +33,8 @@ RewardsNotificationServiceImpl::RewardsNotificationServiceImpl(Profile* profile) : profile_(profile) { #if BUILDFLAG(ENABLE_EXTENSIONS) extension_rewards_notification_service_observer_ = - std::make_unique(profile); + std::make_unique + (profile); AddObserver(extension_rewards_notification_service_observer_.get()); #endif ReadRewardsNotificationsJSON(); diff --git a/components/brave_rewards/browser/rewards_service.h b/components/brave_rewards/browser/rewards_service.h index 85722b341d29..acfa3ec147fb 100644 --- a/components/brave_rewards/browser/rewards_service.h +++ b/components/brave_rewards/browser/rewards_service.h @@ -17,6 +17,7 @@ #include "brave/components/brave_rewards/browser/content_site.h" #include "brave/components/brave_rewards/browser/publisher_banner.h" #include "brave/components/brave_rewards/browser/rewards_internals_info.h" +#include "brave/components/brave_rewards/browser/rewards_notification_service.h" #include "build/build_config.h" #include "components/sessions/core/session_id.h" #include "components/keyed_service/core/keyed_service.h" @@ -205,6 +206,9 @@ class RewardsService : public KeyedService { virtual void SaveRecurringTip(const std::string& publisher_key, const int amount) = 0; + virtual const RewardsNotificationService::RewardsNotificationsMap& + GetAllNotifications() = 0; + protected: base::ObserverList observers_; diff --git a/components/brave_rewards/browser/rewards_service_factory.cc b/components/brave_rewards/browser/rewards_service_factory.cc index da6427d62a22..d0135951b76f 100644 --- a/components/brave_rewards/browser/rewards_service_factory.cc +++ b/components/brave_rewards/browser/rewards_service_factory.cc @@ -1,7 +1,10 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public +/* Copyright (c) 2019 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 http://mozilla.org/MPL/2.0/. */ +#include + #include "brave/components/brave_rewards/browser/rewards_service_factory.h" #include "brave/components/brave_rewards/browser/buildflags/buildflags.h" @@ -9,6 +12,11 @@ #include "chrome/browser/profiles/incognito_helpers.h" #include "chrome/browser/profiles/profile.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "extensions/buildflags/buildflags.h" + +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/browser/event_router_factory.h" +#endif #if BUILDFLAG(BRAVE_REWARDS_ENABLED) #include "brave/components/brave_rewards/browser/rewards_service_impl.h" @@ -16,12 +24,18 @@ namespace brave_rewards { +RewardsService* testing_service_; + // static RewardsService* RewardsServiceFactory::GetForProfile( Profile* profile) { if (profile->IsOffTheRecord()) return NULL; + if (testing_service_) { + return testing_service_; + } + return static_cast( GetInstance()->GetServiceForBrowserContext(profile, true)); } @@ -35,6 +49,9 @@ RewardsServiceFactory::RewardsServiceFactory() : BrowserContextKeyedServiceFactory( "RewardsService", BrowserContextDependencyManager::GetInstance()) { +#if BUILDFLAG(ENABLE_EXTENSIONS) + DependsOn(extensions::EventRouterFactory::GetInstance()); +#endif } RewardsServiceFactory::~RewardsServiceFactory() { @@ -52,6 +69,11 @@ KeyedService* RewardsServiceFactory::BuildServiceInstanceFor( #endif } +// static +void RewardsServiceFactory::SetServiceForTesting(RewardsService* service) { + testing_service_ = service; +} + content::BrowserContext* RewardsServiceFactory::GetBrowserContextToUse( content::BrowserContext* context) const { if (context->IsOffTheRecord()) diff --git a/components/brave_rewards/browser/rewards_service_factory.h b/components/brave_rewards/browser/rewards_service_factory.h index f82d62c7ac53..207b7f6cc6e0 100644 --- a/components/brave_rewards/browser/rewards_service_factory.h +++ b/components/brave_rewards/browser/rewards_service_factory.h @@ -1,12 +1,14 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public +/* Copyright (c) 2019 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 http://mozilla.org/MPL/2.0/. */ -#ifndef BRAVE_BROWSER_BRAVE_REWARDS_REWARDS_SERVICE_FACTORY_H_ -#define BRAVE_BROWSER_BRAVE_REWARDS_REWARDS_SERVICE_FACTORY_H_ +#ifndef BRAVE_COMPONENTS_BRAVE_REWARDS_BROWSER_REWARDS_SERVICE_FACTORY_H_ +#define BRAVE_COMPONENTS_BRAVE_REWARDS_BROWSER_REWARDS_SERVICE_FACTORY_H_ #include "base/memory/singleton.h" #include "components/keyed_service/content/browser_context_keyed_service_factory.h" +#include "brave/components/brave_rewards/browser/rewards_service.h" class Profile; @@ -21,6 +23,8 @@ class RewardsServiceFactory : public BrowserContextKeyedServiceFactory { static RewardsServiceFactory* GetInstance(); + static void SetServiceForTesting(RewardsService* service); + private: friend struct base::DefaultSingletonTraits; @@ -37,6 +41,6 @@ class RewardsServiceFactory : public BrowserContextKeyedServiceFactory { DISALLOW_COPY_AND_ASSIGN(RewardsServiceFactory); }; -} // namepsace brave_rewards +} // namespace brave_rewards -#endif // BRAVE_BROWSER_BRAVE_REWARDS_REWARDS_SERVICE_FACTORY_H_ +#endif // BRAVE_COMPONENTS_BRAVE_REWARDS_BROWSER_REWARDS_SERVICE_FACTORY_H_ diff --git a/components/brave_rewards/browser/rewards_service_impl.cc b/components/brave_rewards/browser/rewards_service_impl.cc index a4902ec19252..f1a7d5f65837 100644 --- a/components/brave_rewards/browser/rewards_service_impl.cc +++ b/components/brave_rewards/browser/rewards_service_impl.cc @@ -1507,7 +1507,7 @@ void RewardsServiceImpl::SetRewardsMainEnabledPref(bool enabled) { void RewardsServiceImpl::SetRewardsMainEnabledMigratedPref(bool enabled) { profile_->GetPrefs()->SetBoolean( - prefs::kBraveRewardsEnabledMigrated, enabled); + prefs::kBraveRewardsEnabledMigrated, true); } void RewardsServiceImpl::SetCatalogIssuers(const std::string& json) { @@ -2909,4 +2909,9 @@ void RewardsServiceImpl::OnRefreshPublisher( std::move(callback).Run(verified, publisher_key); } +const RewardsNotificationService::RewardsNotificationsMap& +RewardsServiceImpl::GetAllNotifications() { + return notification_service_->GetAllNotifications(); +} + } // namespace brave_rewards diff --git a/components/brave_rewards/browser/rewards_service_impl.h b/components/brave_rewards/browser/rewards_service_impl.h index f8aee947be13..f0bede4fddb1 100644 --- a/components/brave_rewards/browser/rewards_service_impl.h +++ b/components/brave_rewards/browser/rewards_service_impl.h @@ -207,6 +207,9 @@ class RewardsServiceImpl : public RewardsService, void SaveRecurringTip(const std::string& publisher_key, const int amount) override; + const RewardsNotificationService::RewardsNotificationsMap& + GetAllNotifications() override; + // Testing methods void SetLedgerEnvForTesting(); void StartAutoContributeForTest(); diff --git a/components/brave_rewards/resources/extension/brave_rewards/_locales/en_US/messages.json b/components/brave_rewards/resources/extension/brave_rewards/_locales/en_US/messages.json index c903f184b6a3..d2adaa1c5eed 100644 --- a/components/brave_rewards/resources/extension/brave_rewards/_locales/en_US/messages.json +++ b/components/brave_rewards/resources/extension/brave_rewards/_locales/en_US/messages.json @@ -163,6 +163,14 @@ "message": "ok", "description": "Used in notification to dismiss notification" }, + "braveAdsLaunchMsg": { + "message": "Now you can earn by viewing ads.", + "description": "Message for ads launch notification" + }, + "braveAdsLaunchTitle": { + "message": "Brave Ads has arrived!", + "description": "Message used in notification to let users know Ads is available" + }, "braveAdsTitle": { "message": "Brave Ads", "description": "Notification title when we display info about ads" @@ -396,5 +404,9 @@ "bat": { "message": "BAT", "description": "BAT text for displaying converted tip amount." + }, + "turnOnAds": { + "message": "Turn on Ads", + "description": "Prompt to turn on Ads via notification" } } diff --git a/components/brave_rewards/resources/extension/brave_rewards/actions/rewards_panel_actions.ts b/components/brave_rewards/resources/extension/brave_rewards/actions/rewards_panel_actions.ts index 41f07a97d92e..c402128dbefe 100644 --- a/components/brave_rewards/resources/extension/brave_rewards/actions/rewards_panel_actions.ts +++ b/components/brave_rewards/resources/extension/brave_rewards/actions/rewards_panel_actions.ts @@ -137,3 +137,6 @@ export const refreshPublisher = (verified: boolean, publisherKey: string) => act verified, publisherKey }) +export const onAllNotifications = (list: RewardsExtension.Notification[]) => action(types.ON_ALL_NOTIFICATIONS, { + list +}) diff --git a/components/brave_rewards/resources/extension/brave_rewards/background/api/locale_api.ts b/components/brave_rewards/resources/extension/brave_rewards/background/api/locale_api.ts index 28f56d5e7966..6c384eb74dbf 100644 --- a/components/brave_rewards/resources/extension/brave_rewards/background/api/locale_api.ts +++ b/components/brave_rewards/resources/extension/brave_rewards/background/api/locale_api.ts @@ -27,6 +27,8 @@ export const getUIMessages = (): Record => { 'backupWalletNotification', 'backupWalletTitle', 'bat', + 'braveAdsLaunchTitle', + 'braveAdsLaunchMsg', 'braveAdsTitle', 'braveContributeTitle', 'braveRewards', @@ -91,6 +93,7 @@ export const getUIMessages = (): Record => { 'tokenGrant', 'tokenGrantClaimed', 'unVerifiedCheck', + 'turnOnAds', 'unVerifiedPublisher', 'unVerifiedText', 'unVerifiedTextMore', diff --git a/components/brave_rewards/resources/extension/brave_rewards/background/events/rewardsEvents.ts b/components/brave_rewards/resources/extension/brave_rewards/background/events/rewardsEvents.ts index 2d5d089f8c1a..57e127570974 100644 --- a/components/brave_rewards/resources/extension/brave_rewards/background/events/rewardsEvents.ts +++ b/components/brave_rewards/resources/extension/brave_rewards/background/events/rewardsEvents.ts @@ -4,6 +4,10 @@ import rewardsPanelActions from '../actions/rewardsPanelActions' +chrome.braveRewards.getAllNotifications((list: RewardsExtension.Notification[]) => { + rewardsPanelActions.onAllNotifications(list) +}) + chrome.braveRewards.onWalletInitialized.addListener((result: RewardsExtension.Result) => { rewardsPanelActions.onWalletInitialized(result) }) diff --git a/components/brave_rewards/resources/extension/brave_rewards/background/reducers/rewards_panel_reducer.ts b/components/brave_rewards/resources/extension/brave_rewards/background/reducers/rewards_panel_reducer.ts index ea65cd0c6e90..e0c1da56f4a4 100644 --- a/components/brave_rewards/resources/extension/brave_rewards/background/reducers/rewards_panel_reducer.ts +++ b/components/brave_rewards/resources/extension/brave_rewards/background/reducers/rewards_panel_reducer.ts @@ -367,6 +367,42 @@ export const rewardsPanelReducer = (state: RewardsExtension.State | undefined, a } break } + case types.ON_ALL_NOTIFICATIONS: { + const list = payload.list + + if (!list) { + break + } + + let notifications: Record = state.notifications + let id = '' + + if (!notifications) { + notifications = [] + } + + list.forEach((notification: RewardsExtension.Notification) => { + id = notification.id + notifications[notification.id] = { + id: notification.id, + type: notification.type, + timestamp: notification.timestamp, + args: notification.args + } + }) + + state = { + ...state, + notifications + } + + if (state.currentNotification === undefined && id) { + state.currentNotification = id + } + + setBadgeText(state) + break + } } return state } diff --git a/components/brave_rewards/resources/extension/brave_rewards/components/app.tsx b/components/brave_rewards/resources/extension/brave_rewards/components/app.tsx index 4dd65ed027cc..bbd74a8c6cc0 100644 --- a/components/brave_rewards/resources/extension/brave_rewards/components/app.tsx +++ b/components/brave_rewards/resources/extension/brave_rewards/components/app.tsx @@ -48,6 +48,10 @@ export class RewardsPanel extends React.Component { chrome.braveRewards.getRecurringTips((tips: RewardsExtension.RecurringTips) => { this.props.actions.onRecurringTips(tips) }) + + chrome.braveRewards.getAllNotifications((list: RewardsExtension.Notification[]) => { + this.props.actions.onAllNotifications(list) + }) } componentDidUpdate (prevProps: Props, prevState: State) { diff --git a/components/brave_rewards/resources/extension/brave_rewards/components/panel.tsx b/components/brave_rewards/resources/extension/brave_rewards/components/panel.tsx index a08b8fa1d3e3..7be3fa298207 100644 --- a/components/brave_rewards/resources/extension/brave_rewards/components/panel.tsx +++ b/components/brave_rewards/resources/extension/brave_rewards/components/panel.tsx @@ -182,10 +182,14 @@ export class Panel extends React.Component { } } - openRewardsPage () { + openRewardsPage (id?: string) { chrome.tabs.create({ - url: 'chrome://rewards' + url: 'brave://rewards' }) + + if (id) { + this.onCloseNotification(id) + } } openRewardsAddFundsPage () { @@ -242,6 +246,9 @@ export class Panel extends React.Component { case 'backupWallet': clickEvent = this.onBackupWallet.bind(this, id) break + case 'ads-launch': + clickEvent = this.openRewardsPage.bind(this, id) + break default: clickEvent = undefined break @@ -266,6 +273,7 @@ export class Panel extends React.Component { let type: NotificationType = '' let text = '' let isAlert = '' + switch (notification.type) { case RewardsNotificationType.REWARDS_NOTIFICATION_AUTO_CONTRIBUTE: { if (!notification.args || @@ -318,6 +326,10 @@ export class Panel extends React.Component { type = 'tipsProcessed' text = getMessage('tipsProcessedNotification') break + case RewardsNotificationType.REWARDS_NOTIFICATION_ADS_LAUNCH: + type = 'ads-launch' + text = getMessage('braveAdsLaunchMsg') + break default: type = '' break @@ -436,6 +448,12 @@ export class Panel extends React.Component { ? this.generateAmounts(publisher) : undefined + if (notification && + notification.notification && + notificationType === 'ads-launch') { + delete notification.notification['date'] + } + const pendingTotal = parseFloat( (pendingContributionTotal || 0).toFixed(1)) diff --git a/components/brave_rewards/resources/extension/brave_rewards/constants/rewards_panel_types.ts b/components/brave_rewards/resources/extension/brave_rewards/constants/rewards_panel_types.ts index 7ed79687c65d..55a9b9d601d9 100644 --- a/components/brave_rewards/resources/extension/brave_rewards/constants/rewards_panel_types.ts +++ b/components/brave_rewards/resources/extension/brave_rewards/constants/rewards_panel_types.ts @@ -34,7 +34,8 @@ export const enum types { REMOVE_RECURRING_TIP = '@@rewards_panel/REMOVE_RECURRING_TIP', ON_RECURRING_TIPS = '@@rewards_panel/ON_RECURRING_TIPS', ON_PUBLISHER_BANNER = '@@rewards_panel/ON_PUBLISHER_BANNER', - ON_PUBLISHER_STATUS_REFRESHED = '@@rewards_panel/ON_PUBLISHER_STATUS_REFRESHED' + ON_PUBLISHER_STATUS_REFRESHED = '@@rewards_panel/ON_PUBLISHER_STATUS_REFRESHED', + ON_ALL_NOTIFICATIONS = '@@rewards_panel/ON_ALL_NOTIFICATIONS' } // Note: This declaration must match the RewardsNotificationType enum in @@ -48,5 +49,6 @@ export const enum RewardsNotificationType { REWARDS_NOTIFICATION_IMPENDING_CONTRIBUTION, REWARDS_NOTIFICATION_INSUFFICIENT_FUNDS, REWARDS_NOTIFICATION_BACKUP_WALLET, - REWARDS_NOTIFICATION_TIPS_PROCESSED + REWARDS_NOTIFICATION_TIPS_PROCESSED, + REWARDS_NOTIFICATION_ADS_LAUNCH } diff --git a/components/definitions/chromel.d.ts b/components/definitions/chromel.d.ts index 1315e75aa5db..bbaef52d720a 100644 --- a/components/definitions/chromel.d.ts +++ b/components/definitions/chromel.d.ts @@ -72,6 +72,7 @@ declare namespace chrome.braveRewards { addListener: (callback: (success: boolean) => void) => void } const refreshPublisher: (publisherKey: string, callback: (enabled: boolean, publisherKey: string) => void) => {} + const getAllNotifications: (callback: (list: RewardsExtension.Notification[]) => void) => {} } declare namespace chrome.rewardsNotifications { diff --git a/components/resources/brave_components_strings.grd b/components/resources/brave_components_strings.grd index bd4e816f9ca7..4f29577df1a4 100644 --- a/components/resources/brave_components_strings.grd +++ b/components/resources/brave_components_strings.grd @@ -304,6 +304,8 @@ Amount Backup Get paid to view relevant ads that respect your privacy. + Now you can earn by viewing ads. + Brave Ads has arrived! Ads Support your favorite sites just by browsing – or tip a site any time you like. Auto-Contribute @@ -466,6 +468,7 @@ tokens Total Transactions + Turn on Ads This enables both ads and automatic contributions. You can turn them on or off separately at any time. Activate Rewards Type diff --git a/components/test/brave_rewards/extension/brave_rewards/background/reducers/rewards_panel_reducer_test.ts b/components/test/brave_rewards/extension/brave_rewards/background/reducers/rewards_panel_reducer_test.ts index 3ae61e97e6e7..713e58a89487 100644 --- a/components/test/brave_rewards/extension/brave_rewards/background/reducers/rewards_panel_reducer_test.ts +++ b/components/test/brave_rewards/extension/brave_rewards/background/reducers/rewards_panel_reducer_test.ts @@ -395,4 +395,76 @@ describe('rewards panel reducer', () => { expect(state.rewardsPanelData).toEqual(expectedState) }) }) + + describe('ON_ALL_NOTIFICATIONS', () => { + it('list is undefined', () => { + let state = reducers({ rewardsPanelData: defaultState }, { + type: types.ON_ALL_NOTIFICATIONS, + payload: { + list: undefined + } + }) + + expect(state.rewardsPanelData).toEqual(defaultState) + }) + + it('list is empty and it was not defined before', () => { + let state = reducers({ rewardsPanelData: defaultState }, { + type: types.ON_ALL_NOTIFICATIONS, + payload: { + list: [] + } + }) + + const expectedState: Rewards.State = { + ...defaultState, + notifications: {} + } + + expect(state.rewardsPanelData).toEqual(expectedState) + }) + + it('list is ok', () => { + let state = reducers({ rewardsPanelData: defaultState }, { + type: types.ON_ALL_NOTIFICATIONS, + payload: { + list: [ + { + id: 'notification_1', + type: 1, + timestamp: 0, + args: ['working'] + }, + { + id: 'notification_2', + type: 1, + timestamp: 1, + args: [] + } + ] + } + }) + + const expectedState: Rewards.State = { + ...defaultState, + currentNotification: 'notification_2', + notifications: { + 'notification_1': { + id: 'notification_1', + type: 1, + timestamp: 0, + args: ['working'] + }, + 'notification_2': { + id: 'notification_2', + type: 1, + timestamp: 1, + args: [] + } + } + } + + expect(state.rewardsPanelData).toEqual(expectedState) + }) + }) }) diff --git a/test/BUILD.gn b/test/BUILD.gn index f8312816c70e..bae3da2e905a 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -1,4 +1,5 @@ import("//brave/build/config.gni") +import("//brave/components/brave_ads/browser/buildflags/buildflags.gni") import("//brave/components/brave_rewards/browser/buildflags/buildflags.gni") import("//testing/test.gni") import("//third_party/widevine/cdm/widevine.gni") @@ -102,6 +103,12 @@ test("brave_unit_tests") { "../../components/domain_reliability/test_util.h", ] + if (brave_ads_enabled) { + sources += [ + "//brave/components/brave_ads/browser/ads_service_impl_unittest.cc" + ] + } + if (brave_rewards_enabled) { sources += [ "//brave/vendor/bat-native-ledger/src/bat/ledger/internal/media/helper_unittest.cc", @@ -167,6 +174,7 @@ test("brave_unit_tests") { deps = [ "//brave/components/brave_rewards/browser:testutil", + "//brave/components/brave_ads/browser:testutil", "//brave/components/brave_sync:testutil", "//brave/vendor/bat-native-rapidjson", "//chrome:browser_dependencies",