From b8968cbc35fa76a835d7ddd90a15e3cb38ba6192 Mon Sep 17 00:00:00 2001 From: Terry Mancey Date: Mon, 1 Jul 2019 15:16:13 +0100 Subject: [PATCH] Fix ad notifications fail to open if Brave is closed after the Ad notification is shown --- .../brave_ads/browser/ad_notification.cc | 15 +- .../brave_ads/browser/ad_notification.h | 12 +- components/brave_ads/browser/ads_service.h | 17 +- .../brave_ads/browser/ads_service_impl.cc | 372 ++++++++++-------- .../brave_ads/browser/ads_service_impl.h | 38 +- .../brave_ads/browser/ads_tab_helper.cc | 4 +- .../bat_ads/bat_ads_client_mojo_bridge.cc | 14 +- .../bat_ads/bat_ads_client_mojo_bridge.h | 2 +- components/services/bat_ads/bat_ads_impl.cc | 137 ++++--- components/services/bat_ads/bat_ads_impl.h | 78 +++- .../services/bat_ads/bat_ads_service_impl.cc | 17 +- .../services/bat_ads/bat_ads_service_impl.h | 6 +- .../public/cpp/ads_client_mojo_bridge.cc | 13 +- .../public/cpp/ads_client_mojo_bridge.h | 3 +- .../bat_ads/public/interfaces/bat_ads.mojom | 31 +- vendor/bat-native-ads/BUILD.gn | 5 +- vendor/bat-native-ads/README.md | 161 ++++---- vendor/bat-native-ads/include/bat/ads/ads.h | 98 ++--- .../include/bat/ads/ads_client.h | 8 +- .../include/bat/ads/notification_event_type.h | 20 + .../include/bat/ads/notification_info.h | 3 +- .../src/bat/ads/internal/ads_client_mock.h | 5 +- .../src/bat/ads/internal/ads_impl.cc | 305 +++++++++----- .../src/bat/ads/internal/ads_impl.h | 61 ++- .../src/bat/ads/internal/ads_tabs_unittest.cc | 14 +- .../src/bat/ads/internal/client.cc | 40 +- .../src/bat/ads/internal/client.h | 9 +- .../ads/internal}/notification_result_type.h | 0 .../src/bat/ads/internal/notifications.cc | 371 +++++++++++++++++ .../src/bat/ads/internal/notifications.h | 97 +++++ .../src/bat/ads/notification_info.cc | 9 + .../bat/confirmations/notification_info.h | 1 + .../internal/confirmations_impl.cc | 16 +- .../src/bat/ledger/internal/ledger_impl.cc | 1 + vendor/brave-ios/Ads/BATBraveAds.mm | 13 +- .../brave-ios/Ads/Generated/NativeAdsClient.h | 2 +- .../Ads/Generated/NativeAdsClient.mm | 3 - .../Ads/Generated/NativeAdsClientBridge.h | 2 +- 38 files changed, 1399 insertions(+), 604 deletions(-) create mode 100644 vendor/bat-native-ads/include/bat/ads/notification_event_type.h rename vendor/bat-native-ads/{include/bat/ads => src/bat/ads/internal}/notification_result_type.h (100%) create mode 100644 vendor/bat-native-ads/src/bat/ads/internal/notifications.cc create mode 100644 vendor/bat-native-ads/src/bat/ads/internal/notifications.h diff --git a/components/brave_ads/browser/ad_notification.cc b/components/brave_ads/browser/ad_notification.cc index 785f76a6b80..9f791cb2142 100644 --- a/components/brave_ads/browser/ad_notification.cc +++ b/components/brave_ads/browser/ad_notification.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/. */ @@ -13,16 +14,13 @@ namespace brave_ads { namespace { -const char kNotifierIdPrefix[] = "service.ads_service."; const char kNotifierId[] = "service.ads_service"; } // namespace // static std::unique_ptr CreateAdNotification( - const ads::NotificationInfo& notification_info, - std::string* notification_id) { - *notification_id = kNotifierIdPrefix + notification_info.uuid; + const ads::NotificationInfo& notification_info) { message_center::RichNotificationData notification_data; base::string16 advertiser; @@ -42,16 +40,17 @@ std::unique_ptr CreateAdNotification( notification_data.context_message = base::ASCIIToUTF16(" "); auto notification = std::make_unique( message_center::NOTIFICATION_TYPE_SIMPLE, - *notification_id, + notification_info.id, advertiser, text, gfx::Image(), base::string16(), - GURL("chrome://brave_ads/?" + *notification_id), + GURL("chrome://brave_ads/?" + notification_info.id), message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT, - kNotifierId), + kNotifierId), notification_data, nullptr); + #if !defined(OS_MACOSX) || defined(OFFICIAL_BUILD) // set_never_timeout uses an XPC service which requires signing // so for now we don't set this for macos dev builds diff --git a/components/brave_ads/browser/ad_notification.h b/components/brave_ads/browser/ad_notification.h index 66643d19f9f..867e46bc3f8 100644 --- a/components/brave_ads/browser/ad_notification.h +++ b/components/brave_ads/browser/ad_notification.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_ADS_BROWSER_AD_NOTIFICATION_ -#define BRAVE_COMPONENTS_BRAVE_ADS_BROWSER_AD_NOTIFICATION_ +#ifndef BRAVE_COMPONENTS_BRAVE_ADS_BROWSER_AD_NOTIFICATION_H_ +#define BRAVE_COMPONENTS_BRAVE_ADS_BROWSER_AD_NOTIFICATION_H_ #include #include @@ -20,9 +21,8 @@ class Notification; namespace brave_ads { std::unique_ptr CreateAdNotification( - const ads::NotificationInfo& notification_info, - std::string* notification_id); + const ads::NotificationInfo& notification_info); } // namespace brave_ads -#endif // BRAVE_COMPONENTS_BRAVE_ADS_BROWSER_AD_NOTIFICATION_ +#endif // BRAVE_COMPONENTS_BRAVE_ADS_BROWSER_AD_NOTIFICATION_H_ diff --git a/components/brave_ads/browser/ads_service.h b/components/brave_ads/browser/ads_service.h index 6944e831115..c30191f6cb3 100644 --- a/components/brave_ads/browser/ads_service.h +++ b/components/brave_ads/browser/ads_service.h @@ -32,17 +32,18 @@ class AdsService : public KeyedService { virtual void SetAdsPerHour(const uint64_t ads_per_hour) = 0; // ads::Ads proxy - virtual void TabUpdated( - SessionID tab_id, - const GURL& url, - const bool is_active) = 0; - virtual void TabClosed(SessionID tab_id) = 0; - virtual void OnMediaStart(SessionID tab_id) = 0; - virtual void OnMediaStop(SessionID tab_id) = 0; + virtual void SetConfirmationsIsReady(const bool is_ready) = 0; + virtual void ChangeLocale(const std::string& locale) = 0; virtual void ClassifyPage( const std::string& url, const std::string& page) = 0; - virtual void SetConfirmationsIsReady(const bool is_ready) = 0; + virtual void OnMediaStart(SessionID tab_id) = 0; + virtual void OnMediaStop(SessionID tab_id) = 0; + virtual void OnTabUpdated( + SessionID tab_id, + const GURL& url, + const bool is_active) = 0; + virtual void OnTabClosed(SessionID tab_id) = 0; private: DISALLOW_COPY_AND_ASSIGN(AdsService); diff --git a/components/brave_ads/browser/ads_service_impl.cc b/components/brave_ads/browser/ads_service_impl.cc index 64751278187..0402c2ead8c 100644 --- a/components/brave_ads/browser/ads_service_impl.cc +++ b/components/brave_ads/browser/ads_service_impl.cc @@ -20,7 +20,7 @@ #include "base/time/time.h" #include "bat/ads/ads.h" #include "bat/ads/notification_info.h" -#include "bat/ads/notification_result_type.h" +#include "bat/ads/notification_event_type.h" #include "bat/ads/resources/grit/bat_ads_resources.h" #include "brave/components/brave_ads/browser/ad_notification.h" #include "brave/components/brave_ads/browser/locale_helper.h" @@ -49,7 +49,7 @@ #include "content/public/browser/network_service_instance.h" #include "content/public/browser/storage_partition.h" #include "content/public/common/service_manager_connection.h" -#include "services/network/public/cpp/network_connection_tracker.h" +#include "net/base/network_change_notifier.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/simple_url_loader.h" #include "services/service_manager/public/cpp/connector.h" @@ -60,7 +60,9 @@ #if defined(OS_ANDROID) #include "chrome/browser/ui/android/tab_model/tab_model_list.h" +#include "chrome/browser/android/tab_android.h" #include "net/android/network_library.h" +#include "chrome/browser/android/service_tab_launcher.h" #endif using brave_rewards::RewardsNotificationService; @@ -108,22 +110,26 @@ class LogStreamImpl : public ads::LogStream { class AdsNotificationHandler : public NotificationHandler { public: explicit AdsNotificationHandler(AdsServiceImpl* ads_service) : - ads_service_(ads_service->AsWeakPtr()) {} + ads_service_(ads_service->AsWeakPtr()) { + } - ~AdsNotificationHandler() override {} + ~AdsNotificationHandler() override { + } // NotificationHandler implementation. - void OnShow(Profile* profile, - const std::string& notification_id) override { + void OnShow( + Profile* profile, + const std::string& notification_id) override { if (ads_service_) ads_service_->OnShow(profile, notification_id); } - void OnClose(Profile* profile, - const GURL& origin, - const std::string& notification_id, - bool by_user, - base::OnceClosure completed_closure) override { + void OnClose( + Profile* profile, + const GURL& origin, + const std::string& notification_id, + bool by_user, + base::OnceClosure completed_closure) override { if (!ads_service_) { std::move(completed_closure).Run(); return; @@ -134,24 +140,34 @@ class AdsNotificationHandler : public NotificationHandler { std::move(completed_closure)); } - void OnClick(Profile* profile, - const GURL& origin, - const std::string& notification_id, - const base::Optional& action_index, - const base::Optional& reply, - base::OnceClosure completed_closure) override { - if (ads_service_ && !action_index.has_value()) { - ads_service_->OpenSettings(profile, origin, true); + void OnClick( + Profile* profile, + const GURL& origin, + const std::string& notification_id, + const base::Optional& action_index, + const base::Optional& reply, + base::OnceClosure completed_closure) override { + if (!ads_service_) { + return; } - } - void DisableNotifications(Profile* profile, - const GURL& origin) override {} + ads_service_->ViewAd(notification_id); + } + void DisableNotifications( + Profile* profile, + const GURL& origin) override { + } void OpenSettings(Profile* profile, const GURL& origin) override { - if (ads_service_) - ads_service_->OpenSettings(profile, origin, false); + if (!ads_service_) { + return; + } + + DCHECK(origin.has_query()); + + auto id = origin.query(); + ads_service_->ViewAd(id); } private: @@ -162,9 +178,8 @@ class AdsNotificationHandler : public NotificationHandler { namespace { -int32_t ToMojomNotificationResultInfoResultType( - ads::NotificationResultInfoResultType result_type) { - return (int32_t)result_type; +int32_t ToMojomNotificationEventType(ads::NotificationEventType type) { + return (int32_t)type; } static std::map g_schema_resource_ids = { @@ -293,9 +308,10 @@ AdsServiceImpl::AdsServiceImpl(Profile* profile) {base::MayBlock(), base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::BLOCK_SHUTDOWN})), base_path_(profile_->GetPath().AppendASCII("ads_service")), + is_initialized_(false), + retry_viewing_ad_with_id_(""), next_timer_id_(0), ads_launch_id_(0), - is_supported_region_(false), bundle_state_backend_( new BundleStateDatabase(base_path_.AppendASCII("bundle_state"))), display_service_(NotificationDisplayService::GetForProfile(profile_)), @@ -341,40 +357,56 @@ AdsServiceImpl::~AdsServiceImpl() { file_task_runner_->DeleteSoon(FROM_HERE, bundle_state_backend_.release()); } -void AdsServiceImpl::OnInitialize() { - ResetTimer(); -} - void AdsServiceImpl::OnCreate() { - if (connected()) { - bat_ads_->Initialize( - base::BindOnce(&AdsServiceImpl::OnInitialize, AsWeakPtr())); + if (!connected()) { + return; } + + bat_ads_->Initialize(base::BindOnce( + &AdsServiceImpl::OnInitialize, AsWeakPtr())); } -void AdsServiceImpl::MaybeStart(bool should_restart) { - if (should_restart) - Shutdown(); +void AdsServiceImpl::OnInitialize(const int32_t result) { + if (result == ads::Result::FAILED) { + LOG(ERROR) << "Failed to initialize ads"; + return; + } - if (!StartService()) { - LOG(ERROR) << "Failed to start Ads service"; + is_initialized_ = true; + + MaybeViewAd(); + + ResetTimer(); +} + +void AdsServiceImpl::MaybeViewAd() { + if (retry_viewing_ad_with_id_.empty()) { return; } - bat_ads_service_->IsSupportedRegion(GetAdsLocale(), - base::BindOnce(&AdsServiceImpl::OnMaybeStartForRegion, - AsWeakPtr(), should_restart)); + ViewAd(retry_viewing_ad_with_id_); + retry_viewing_ad_with_id_ = ""; } -void AdsServiceImpl::OnMaybeStartForRegion( - bool should_restart, - bool is_supported_region) { - is_supported_region_ = is_supported_region; +void AdsServiceImpl::RetryViewingAdWithId(const std::string& id) { + LOG(WARNING) << "Retry viewing ad with id " << id; + retry_viewing_ad_with_id_ = id; +} - if (!is_supported_region_) { - LOG(WARNING) << GetAdsLocale() << " locale does not support Ads"; +void AdsServiceImpl::MaybeStart(bool should_restart) { + if (!IsSupportedRegion()) { + LOG(INFO) << GetAdsLocale() << " locale does not support Ads"; + Shutdown(); + return; + } + if (should_restart) { + LOG(INFO) << "Restarting ads service"; Shutdown(); + } + + if (!StartService()) { + LOG(ERROR) << "Failed to start ads service"; return; } @@ -400,8 +432,9 @@ bool AdsServiceImpl::StartService() { content::ServiceManagerConnection* connection = content::ServiceManagerConnection::GetForProcess(); - if (!connection) + if (!connection) { return false; + } connection->GetConnector()->BindInterface( bat_ads::mojom::kServiceName, &bat_ads_service_); @@ -628,10 +661,19 @@ void AdsServiceImpl::OnFirstLaunchNotificationTimedOut(uint32_t timer_id) { } void AdsServiceImpl::Stop() { - if (connected()) { - // this is kind of weird, but we need to call Initialize on disable too - bat_ads_->Initialize(base::NullCallback()); + if (!connected()) { + Shutdown(); + return; + } + + bat_ads_->Shutdown(base::BindOnce(&AdsServiceImpl::OnShutdown, AsWeakPtr())); +} + +void AdsServiceImpl::OnShutdown(const int32_t result) { + if (result == ads::Result::FAILED) { + LOG(ERROR) << "Failed to shutdown ads"; } + Shutdown(); } @@ -670,18 +712,13 @@ void AdsServiceImpl::Shutdown() { delete loader; } url_loaders_.clear(); + idle_poll_timer_.Stop(); bat_ads_.reset(); bat_ads_client_binding_.Close(); - for (NotificationInfoMap::iterator it = notification_ids_.begin(); - it != notification_ids_.end(); ++it) { - const std::string notification_id = it->first; - display_service_->Close(NotificationHandler::Type::BRAVE_ADS, - notification_id); - } - notification_ids_.clear(); + is_initialized_ = false; } void AdsServiceImpl::MigratePrefs() const { @@ -690,7 +727,7 @@ void AdsServiceImpl::MigratePrefs() const { if (!MigratePrefs(source_version, dest_version, true)) { // Migration dry-run failed, so do not migrate preferences - LOG(ERROR) << "Failed to migrate Ads preferences from version " + LOG(ERROR) << "Failed to migrate ads preferences from version " << source_version << " to " << dest_version; return; @@ -794,7 +831,8 @@ void AdsServiceImpl::OnPrefsChanged(const std::string& pref) { } bool AdsServiceImpl::IsSupportedRegion() const { - return is_supported_region_; + auto locale = LocaleHelper::GetInstance()->GetLocale(); + return ads::Ads::IsSupportedRegion(locale); } bool AdsServiceImpl::IsAdsEnabled() const { @@ -859,23 +897,24 @@ bool AdsServiceImpl::IsForeground() const { return BackgroundHelper::GetInstance()->IsForeground(); } -void AdsServiceImpl::TabUpdated(SessionID tab_id, - const GURL& url, - const bool is_active) { - if (!connected()) +void AdsServiceImpl::OnTabUpdated( + SessionID tab_id, + const GURL& url, + const bool is_active) { + if (!connected()) { return; + } - bat_ads_->TabUpdated(tab_id.id(), - url.spec(), - is_active, - profile_->IsOffTheRecord()); + bat_ads_->OnTabUpdated(tab_id.id(), url.spec(), is_active, + profile_->IsOffTheRecord()); } -void AdsServiceImpl::TabClosed(SessionID tab_id) { - if (!connected()) +void AdsServiceImpl::OnTabClosed(SessionID tab_id) { + if (!connected()) { return; + } - bat_ads_->TabClosed(tab_id.id()); + bat_ads_->OnTabClosed(tab_id.id()); } void AdsServiceImpl::SetConfirmationsIsReady(const bool is_ready) { @@ -885,6 +924,14 @@ void AdsServiceImpl::SetConfirmationsIsReady(const bool is_ready) { bat_ads_->SetConfirmationsIsReady(is_ready); } +void AdsServiceImpl::ChangeLocale(const std::string& locale) { + if (!connected()) { + return; + } + + bat_ads_->ChangeLocale(locale); +} + void AdsServiceImpl::ClassifyPage(const std::string& url, const std::string& page) { if (!connected()) @@ -921,12 +968,24 @@ void AdsServiceImpl::LoadUserModelForLocale( callback(ads::Result::SUCCESS, user_model); } -void AdsServiceImpl::OnURLsDeleted(history::HistoryService* history_service, - const history::DeletionInfo& deletion_info) { - if (!connected()) +void AdsServiceImpl::OnURLsDeleted( + history::HistoryService* history_service, + const history::DeletionInfo& deletion_info) { + if (!connected()) { + return; + } + + bat_ads_->RemoveAllHistory(base::BindOnce( + &AdsServiceImpl::OnRemoveAllHistory, AsWeakPtr())); +} + +void AdsServiceImpl::OnRemoveAllHistory(const int32_t result) { + if (result == ads::Result::FAILED) { + LOG(ERROR) << "Failed to remove all ads history"; return; + } - bat_ads_->RemoveAllHistory(base::NullCallback()); + LOG(INFO) << "Successfully removed all ads history"; } void AdsServiceImpl::OnMediaStart(SessionID tab_id) { @@ -945,23 +1004,24 @@ void AdsServiceImpl::OnMediaStop(SessionID tab_id) { void AdsServiceImpl::ShowNotification( std::unique_ptr info) { - std::string notification_id; - auto notification = - CreateAdNotification(*info, ¬ification_id); - - notification_ids_[notification_id] = std::move(info); + auto notification = CreateAdNotification(*info); - display_service_->Display(NotificationHandler::Type::BRAVE_ADS, *notification, - /*metadata=*/nullptr); + display_service_->Display(NotificationHandler::Type::BRAVE_ADS, + *notification, /*metadata=*/nullptr); +#if !defined(OS_ANDROID) uint32_t timer_id = next_timer_id(); timers_[timer_id] = std::make_unique(); timers_[timer_id]->Start(FROM_HERE, base::TimeDelta::FromSeconds(120), - base::BindOnce( - &AdsServiceImpl::NotificationTimedOut, AsWeakPtr(), - timer_id, notification_id)); + base::BindOnce(&AdsServiceImpl::NotificationTimedOut, AsWeakPtr(), + timer_id, info->id)); +#endif +} + +void AdsServiceImpl::CloseNotification(const std::string& id) { + display_service_->Close(NotificationHandler::Type::BRAVE_ADS, id); } void AdsServiceImpl::SetCatalogIssuers(std::unique_ptr info) { @@ -972,14 +1032,18 @@ void AdsServiceImpl::ConfirmAd(std::unique_ptr info) { rewards_service_->ConfirmAd(info->ToJson()); } -void AdsServiceImpl::NotificationTimedOut(uint32_t timer_id, - const std::string& notification_id) { +void AdsServiceImpl::NotificationTimedOut( + uint32_t timer_id, + const std::string& notification_id) { timers_.erase(timer_id); - if (notification_ids_.find(notification_id) != notification_ids_.end()) { - display_service_->Close(NotificationHandler::Type::BRAVE_ADS, - notification_id); - OnClose(profile_, GURL(), notification_id, false, base::OnceClosure()); + + if (!connected()) { + return; } + + CloseNotification(notification_id); + + OnClose(profile_, GURL(), notification_id, false, base::OnceClosure()); } void AdsServiceImpl::Save(const std::string& name, @@ -1107,87 +1171,87 @@ void AdsServiceImpl::LoadSampleBundle( } bool AdsServiceImpl::IsNetworkConnectionAvailable() { - return !content::GetNetworkConnectionTracker()->IsOffline(); + return !net::NetworkChangeNotifier::IsOffline(); } -void AdsServiceImpl::OnShow(Profile* profile, - const std::string& notification_id) { - if (!connected() || - notification_ids_.find(notification_id) == notification_ids_.end()) +void AdsServiceImpl::OnShow( + Profile* profile, + const std::string& notification_id) { + if (!connected()) { return; + } - bat_ads_->GenerateAdReportingNotificationShownEvent( - notification_ids_[notification_id]->ToJson()); -} - -void AdsServiceImpl::OnClose(Profile* profile, - const GURL& origin, - const std::string& notification_id, - bool by_user, - base::OnceClosure completed_closure) { - if (notification_ids_.find(notification_id) != notification_ids_.end()) { - auto notification_info = base::WrapUnique( - notification_ids_[notification_id].release()); - notification_ids_.erase(notification_id); - - if (connected()) { - auto result_type = by_user - ? ads::NotificationResultInfoResultType::DISMISSED - : ads::NotificationResultInfoResultType::TIMEOUT; - bat_ads_->GenerateAdReportingNotificationResultEvent( - notification_info->ToJson(), - ToMojomNotificationResultInfoResultType(result_type)); - } + bat_ads_->OnNotificationEvent(notification_id, + ToMojomNotificationEventType(ads::NotificationEventType::VIEWED)); +} + +void AdsServiceImpl::OnClose( + Profile* profile, + const GURL& origin, + const std::string& notification_id, + bool by_user, + base::OnceClosure completed_closure) { + if (connected()) { + auto event_type = by_user + ? ads::NotificationEventType::DISMISSED + : ads::NotificationEventType::TIMEOUT; + + bat_ads_->OnNotificationEvent(notification_id, + ToMojomNotificationEventType(event_type)); } - if (completed_closure) + if (completed_closure) { std::move(completed_closure).Run(); + } } -void AdsServiceImpl::OpenSettings(Profile* profile, - const GURL& origin, - bool should_close) { - DCHECK(origin.has_query()); - auto notification_id = origin.query(); - - if (notification_ids_.find(notification_id) == notification_ids_.end()) +void AdsServiceImpl::ViewAd(const std::string& id) { + if (!connected() || !is_initialized_) { + RetryViewingAdWithId(id); return; + } - auto notification_info = base::WrapUnique( - notification_ids_[notification_id].release()); - notification_ids_.erase(notification_id); + LOG(INFO) << "View ad with id " << id; - if (should_close) - display_service_->Close(NotificationHandler::Type::BRAVE_ADS, - notification_id); + bat_ads_->GetNotificationForId( + id, base::BindOnce(&AdsServiceImpl::OnViewAd, AsWeakPtr())); +} - if (connected()) { - bat_ads_->GenerateAdReportingNotificationResultEvent( - notification_info->ToJson(), - ToMojomNotificationResultInfoResultType( - ads::NotificationResultInfoResultType::CLICKED)); - } +void AdsServiceImpl::OnViewAd(const std::string& json) { + ads::NotificationInfo notification; + notification.FromJson(json); + + bat_ads_->OnNotificationEvent(notification.id, + ToMojomNotificationEventType(ads::NotificationEventType::CLICKED)); + + OpenNewTabWithUrl(notification.url); +} - GURL url(notification_info->url); - if (!url.is_valid()) { - LOG(WARNING) << "Invalid notification URL: " << notification_info->url; +void AdsServiceImpl::OpenNewTabWithUrl(const std::string& url) { + GURL gurl(url); + if (!gurl.is_valid()) { + LOG(WARNING) << "Invalid URL: " << url; return; } #if defined(OS_ANDROID) - NavigateParams nav_params(profile, url, ui::PAGE_TRANSITION_LINK); + const content::OpenURLParams params(gurl, content::Referrer(), + WindowOpenDisposition::NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_LINK, + true); + + base::Callback callback = + base::Bind([] (content::WebContents*) {}); + + ServiceTabLauncher::GetInstance()->LaunchTab(profile_, params, callback); #else - Browser* browser = chrome::FindTabbedBrowser(profile, false); - if (!browser) - browser = new Browser(Browser::CreateParams(profile, true)); + Browser* browser = chrome::FindTabbedBrowser(profile_, false); + if (!browser) { + browser = new Browser(Browser::CreateParams(profile_, true)); + } - NavigateParams nav_params(browser, url, ui::PAGE_TRANSITION_LINK); -#endif + NavigateParams nav_params(browser, gurl, ui::PAGE_TRANSITION_LINK); nav_params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB; nav_params.window_action = NavigateParams::SHOW_WINDOW; -#if defined(OS_ANDROID) - TabModelList::HandlePopupNavigation(&nav_params); -#else Navigate(&nav_params); #endif } @@ -1207,10 +1271,6 @@ void AdsServiceImpl::GetClientInfo(ads::ClientInfo* client_info) const { #endif } -const std::string AdsServiceImpl::GenerateUUID() const { - return base::GenerateGUID(); -} - const std::vector AdsServiceImpl::GetLocales() const { std::vector locales; diff --git a/components/brave_ads/browser/ads_service_impl.h b/components/brave_ads/browser/ads_service_impl.h index e33cc7c9e13..2da5642a1be 100644 --- a/components/brave_ads/browser/ads_service_impl.h +++ b/components/brave_ads/browser/ads_service_impl.h @@ -69,15 +69,16 @@ class AdsServiceImpl : public AdsService, void SetAdsPerHour(const uint64_t ads_per_hour) override; - void TabUpdated( + void SetConfirmationsIsReady(const bool is_ready) override; + void ChangeLocale(const std::string& locale) override; + void ClassifyPage(const std::string& url, const std::string& page) override; + void OnMediaStart(SessionID tab_id) override; + void OnMediaStop(SessionID tab_id) override; + void OnTabUpdated( SessionID tab_id, const GURL& url, const bool is_active) override; - void TabClosed(SessionID tab_id) override; - void OnMediaStart(SessionID tab_id) override; - void OnMediaStop(SessionID tab_id) override; - void ClassifyPage(const std::string& url, const std::string& page) override; - void SetConfirmationsIsReady(const bool is_ready) override; + void OnTabClosed(SessionID tab_id) override; void Shutdown() override; @@ -90,9 +91,6 @@ class AdsServiceImpl : public AdsService, private: friend class AdsNotificationHandler; - typedef std::map> - NotificationInfoMap; - void Start(); bool StartService(); void UpdateIsProductionFlag(); @@ -112,18 +110,17 @@ class AdsServiceImpl : public AdsService, const std::string& notification_id, bool by_user, base::OnceClosure completed_closure); - void OpenSettings( - Profile* profile, - const GURL& origin, - bool should_close); + void ViewAd(const std::string& id); + void OnViewAd(const std::string& json); + void OpenNewTabWithUrl(const std::string& url); // AdsClient implementation bool IsForeground() const override; const std::string GetAdsLocale() const override; void GetClientInfo(ads::ClientInfo* info) const override; const std::vector GetLocales() const override; - const std::string GenerateUUID() const override; void ShowNotification(std::unique_ptr info) override; + void CloseNotification(const std::string& id) override; void SetCatalogIssuers(std::unique_ptr info) override; void ConfirmAd(std::unique_ptr info) override; uint32_t SetTimer(const uint64_t time_offset) override; @@ -199,14 +196,15 @@ class AdsServiceImpl : public AdsService, int GetPrefsVersion() const; void OnPrefsChanged(const std::string& pref); void OnCreate(); - void OnInitialize(); + void OnInitialize(const int32_t result); + void OnShutdown(const int32_t result); + void OnRemoveAllHistory(const int32_t result); void MaybeStart(bool should_restart); - void OnMaybeStartForRegion( - bool should_restart, - bool is_supported_region); void NotificationTimedOut( uint32_t timer_id, const std::string& notification_id); + void MaybeViewAd(); + void RetryViewingAdWithId(const std::string& id); void MaybeShowFirstLaunchNotification(); bool ShouldShowFirstLaunchNotification(); void RemoveFirstLaunchNotification(); @@ -227,9 +225,10 @@ class AdsServiceImpl : public AdsService, const scoped_refptr file_task_runner_; const base::FilePath base_path_; std::map> timers_; + bool is_initialized_; + std::string retry_viewing_ad_with_id_; 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 brave_rewards::RewardsService* rewards_service_; // NOT OWNED @@ -247,7 +246,6 @@ class AdsServiceImpl : public AdsService, bat_ads::mojom::BatAdsAssociatedPtr bat_ads_; bat_ads::mojom::BatAdsServicePtr bat_ads_service_; - NotificationInfoMap notification_ids_; base::flat_set url_loaders_; DISALLOW_COPY_AND_ASSIGN(AdsServiceImpl); diff --git a/components/brave_ads/browser/ads_tab_helper.cc b/components/brave_ads/browser/ads_tab_helper.cc index c22fc68e574..4b3175f996e 100644 --- a/components/brave_ads/browser/ads_tab_helper.cc +++ b/components/brave_ads/browser/ads_tab_helper.cc @@ -144,7 +144,7 @@ void AdsTabHelper::TabUpdated() { if (!ads_service_) return; - ads_service_->TabUpdated( + ads_service_->OnTabUpdated( tab_id_, web_contents()->GetURL(), is_active_ && is_browser_active_); @@ -181,7 +181,7 @@ void AdsTabHelper::OnVisibilityChanged(content::Visibility visibility) { void AdsTabHelper::WebContentsDestroyed() { if (ads_service_) { - ads_service_->TabClosed(tab_id_); + ads_service_->OnTabClosed(tab_id_); ads_service_ = nullptr; } } diff --git a/components/services/bat_ads/bat_ads_client_mojo_bridge.cc b/components/services/bat_ads/bat_ads_client_mojo_bridge.cc index 2292e052954..a0b3eba8670 100644 --- a/components/services/bat_ads/bat_ads_client_mojo_bridge.cc +++ b/components/services/bat_ads/bat_ads_client_mojo_bridge.cc @@ -138,21 +138,19 @@ const std::vector BatAdsClientMojoBridge::GetLocales() const { return locales; } -const std::string BatAdsClientMojoBridge::GenerateUUID() const { +void BatAdsClientMojoBridge::ShowNotification( + std::unique_ptr info) { if (!connected()) - return ""; + return; - std::string uuid; - bat_ads_client_->GenerateUUID(&uuid); - return uuid; + bat_ads_client_->ShowNotification(info->ToJson()); } -void BatAdsClientMojoBridge::ShowNotification( - std::unique_ptr info) { +void BatAdsClientMojoBridge::CloseNotification(const std::string& id) { if (!connected()) return; - bat_ads_client_->ShowNotification(info->ToJson()); + bat_ads_client_->CloseNotification(id); } void BatAdsClientMojoBridge::SetCatalogIssuers( diff --git a/components/services/bat_ads/bat_ads_client_mojo_bridge.h b/components/services/bat_ads/bat_ads_client_mojo_bridge.h index 3020fa37227..63a4964e25b 100644 --- a/components/services/bat_ads/bat_ads_client_mojo_bridge.h +++ b/components/services/bat_ads/bat_ads_client_mojo_bridge.h @@ -29,8 +29,8 @@ class BatAdsClientMojoBridge : public ads::AdsClient { uint64_t GetAdsPerDay() const override; void GetClientInfo(ads::ClientInfo* info) const override; const std::vector GetLocales() const override; - const std::string GenerateUUID() const override; void ShowNotification(std::unique_ptr info) override; + void CloseNotification(const std::string& id) override; void SetCatalogIssuers(std::unique_ptr info) override; void ConfirmAd(std::unique_ptr info) override; uint32_t SetTimer(const uint64_t time_offset) override; diff --git a/components/services/bat_ads/bat_ads_impl.cc b/components/services/bat_ads/bat_ads_impl.cc index 1fe88b8d157..77eb82a01da 100644 --- a/components/services/bat_ads/bat_ads_impl.cc +++ b/components/services/bat_ads/bat_ads_impl.cc @@ -10,40 +10,84 @@ #include "bat/ads/ads.h" #include "brave/components/services/bat_ads/bat_ads_client_mojo_bridge.h" +using std::placeholders::_1; + namespace bat_ads { namespace { -ads::NotificationResultInfoResultType ToNotificationResultInfoResultType( - int32_t result_type) { - return (ads::NotificationResultInfoResultType)result_type; +ads::Result ToMojomResult(int32_t result) { + return (ads::Result)result; } +ads::NotificationEventType ToMojomNotificationEventType(int32_t event_type) { + return (ads::NotificationEventType)event_type; } -BatAdsImpl::BatAdsImpl(mojom::BatAdsClientAssociatedPtrInfo client_info) - : bat_ads_client_mojo_proxy_( - new BatAdsClientMojoBridge(std::move(client_info))), - ads_(ads::Ads::CreateInstance(bat_ads_client_mojo_proxy_.get())) {} +} // namespace + +BatAdsImpl::BatAdsImpl(mojom::BatAdsClientAssociatedPtrInfo client_info) : + bat_ads_client_mojo_proxy_( + new BatAdsClientMojoBridge(std::move(client_info))), + ads_(ads::Ads::CreateInstance(bat_ads_client_mojo_proxy_.get())) {} BatAdsImpl::~BatAdsImpl() {} void BatAdsImpl::Initialize(InitializeCallback callback) { - // TODO(Terry Mancey): Initialize needs a real callback - ads_->Initialize(); - std::move(callback).Run(); + auto* holder = new CallbackHolder(AsWeakPtr(), + std::move(callback)); + + auto initialize_callback = std::bind(BatAdsImpl::OnInitialize, holder, _1); + ads_->Initialize(initialize_callback); +} + +void BatAdsImpl::OnInitialize( + CallbackHolder* holder, + const int32_t result) { + if (holder->is_valid()) { + std::move(holder->get()).Run(ToMojomResult(result)); + } + + delete holder; +} + +void BatAdsImpl::Shutdown(ShutdownCallback callback) { + auto* holder = new CallbackHolder(AsWeakPtr(), + std::move(callback)); + + auto shutdown_callback = std::bind(BatAdsImpl::OnShutdown, holder, _1); + ads_->Shutdown(shutdown_callback); +} + +void BatAdsImpl::OnShutdown( + CallbackHolder* holder, + const int32_t result) { + if (holder->is_valid()) { + std::move(holder->get()).Run(ToMojomResult(result)); + } + + delete holder; } -void BatAdsImpl::ClassifyPage(const std::string& url, - const std::string& page) { +void BatAdsImpl::SetConfirmationsIsReady(const bool is_ready) { + ads_->SetConfirmationsIsReady(is_ready); +} + +void BatAdsImpl::ChangeLocale(const std::string& locale) { + ads_->ChangeLocale(locale); +} + +void BatAdsImpl::ClassifyPage( + const std::string& url, + const std::string& page) { ads_->ClassifyPage(url, page); } -void BatAdsImpl::TabClosed(int32_t tab_id) { - ads_->TabClosed(tab_id); +void BatAdsImpl::ServeSampleAd() { + ads_->ServeSampleAd(); } -void BatAdsImpl::OnTimer(uint32_t timer_id) { +void BatAdsImpl::OnTimer(const uint32_t timer_id) { ads_->OnTimer(timer_id); } @@ -63,52 +107,57 @@ void BatAdsImpl::OnBackground() { ads_->OnBackground(); } -void BatAdsImpl::OnMediaPlaying(int32_t tab_id) { +void BatAdsImpl::OnMediaPlaying(const int32_t tab_id) { ads_->OnMediaPlaying(tab_id); } -void BatAdsImpl::OnMediaStopped(int32_t tab_id) { +void BatAdsImpl::OnMediaStopped(const int32_t tab_id) { ads_->OnMediaStopped(tab_id); } -void BatAdsImpl::TabUpdated(int32_t tab_id, - const std::string& url, - bool is_active, - bool is_incognito) { - ads_->TabUpdated(tab_id, url, is_active, is_incognito); +void BatAdsImpl::OnTabUpdated( + const int32_t tab_id, + const std::string& url, + const bool is_active, + const bool is_incognito) { + ads_->OnTabUpdated(tab_id, url, is_active, is_incognito); } -void BatAdsImpl::RemoveAllHistory(RemoveAllHistoryCallback callback) { - // TODO(Terry Mancey): RemoveAllHistory needs a real callback - ads_->RemoveAllHistory(); - std::move(callback).Run(); +void BatAdsImpl::OnTabClosed(const int32_t tab_id) { + ads_->OnTabClosed(tab_id); } -void BatAdsImpl::SetConfirmationsIsReady(const bool is_ready) { - ads_->SetConfirmationsIsReady(is_ready); +void BatAdsImpl::GetNotificationForId( + const std::string& id, + GetNotificationForIdCallback callback) { + ads::NotificationInfo notification; + ads_->GetNotificationForId(id, ¬ification); + std::move(callback).Run(notification.ToJson()); } -void BatAdsImpl::ServeSampleAd() { - ads_->ServeSampleAd(); +void BatAdsImpl::OnNotificationEvent( + const std::string& id, + const int32_t type) { + ads_->OnNotificationEvent(id, ToMojomNotificationEventType(type)); } -void BatAdsImpl::GenerateAdReportingNotificationShownEvent( - const std::string& notification_info) { - auto info = std::make_unique(); - if (info->FromJson(notification_info) == ads::Result::SUCCESS) { - ads_->GenerateAdReportingNotificationShownEvent(*info); - } +void BatAdsImpl::RemoveAllHistory(RemoveAllHistoryCallback callback) { + auto* holder = new CallbackHolder(AsWeakPtr(), + std::move(callback)); + + auto remove_all_history_callback = + std::bind(BatAdsImpl::OnRemoveAllHistory, holder, _1); + ads_->RemoveAllHistory(remove_all_history_callback); } -void BatAdsImpl::GenerateAdReportingNotificationResultEvent( - const std::string& notification_info, - int32_t result_type) { - auto info = std::make_unique(); - if (info->FromJson(notification_info) == ads::Result::SUCCESS) { - ads_->GenerateAdReportingNotificationResultEvent( - *info, - ToNotificationResultInfoResultType(result_type)); +void BatAdsImpl::OnRemoveAllHistory( + CallbackHolder* holder, + const int32_t result) { + if (holder->is_valid()) { + std::move(holder->get()).Run(ToMojomResult(result)); } + + delete holder; } } // namespace bat_ads diff --git a/components/services/bat_ads/bat_ads_impl.h b/components/services/bat_ads/bat_ads_impl.h index 6874b05c036..cb02a54caa8 100644 --- a/components/services/bat_ads/bat_ads_impl.h +++ b/components/services/bat_ads/bat_ads_impl.h @@ -6,11 +6,16 @@ #ifndef BRAVE_COMPONENTS_SERVICES_BAT_ADS_BAT_ADS_IMPL_H_ #define BRAVE_COMPONENTS_SERVICES_BAT_ADS_BAT_ADS_IMPL_H_ +#include #include #include +#include + +#include "bat/ads/ads.h" #include "brave/components/services/bat_ads/public/interfaces/bat_ads.mojom.h" #include "mojo/public/cpp/bindings/interface_request.h" +#include "base/memory/weak_ptr.h" namespace ads { class Ads; @@ -20,37 +25,74 @@ namespace bat_ads { class BatAdsClientMojoBridge; -class BatAdsImpl : public mojom::BatAds { +class BatAdsImpl : + public mojom::BatAds, + public base::SupportsWeakPtr { public: explicit BatAdsImpl(mojom::BatAdsClientAssociatedPtrInfo client_info); ~BatAdsImpl() override; // Overridden from mojom::BatAds: void Initialize(InitializeCallback callback) override; - void ClassifyPage(const std::string& url, - const std::string& page) override; - void TabClosed(int32_t tab_id) override; - void OnTimer(uint32_t timer_id) override; + void Shutdown(ShutdownCallback callback) override; + void SetConfirmationsIsReady(const bool is_ready) override; + void ChangeLocale(const std::string& locale) override; + void ClassifyPage(const std::string& url, const std::string& page) override; + void ServeSampleAd() override; + void OnTimer(const uint32_t timer_id) override; void OnUnIdle() override; void OnIdle() override; void OnForeground() override; void OnBackground() override; - void OnMediaPlaying(int32_t tab_id) override; - void OnMediaStopped(int32_t tab_id) override; - void TabUpdated(int32_t tab_id, - const std::string& url, - bool is_active, - bool is_incognito) override; + void OnMediaPlaying(const int32_t tab_id) override; + void OnMediaStopped(const int32_t tab_id) override; + void OnTabUpdated( + const int32_t tab_id, + const std::string& url, + const bool is_active, + const bool is_incognito) override; + void OnTabClosed(const int32_t tab_id) override; + void GetNotificationForId( + const std::string& id, + GetNotificationForIdCallback callback) override; + void OnNotificationEvent(const std::string& id, const int32_t type) override; void RemoveAllHistory(RemoveAllHistoryCallback callback) override; - void SetConfirmationsIsReady(const bool is_ready) override; - void ServeSampleAd() override; - void GenerateAdReportingNotificationShownEvent( - const std::string& notification_info) override; - void GenerateAdReportingNotificationResultEvent( - const std::string& notification_info, - int32_t event_type) override; private: + // Workaround to pass base::OnceCallback into std::bind + template + class CallbackHolder { + public: + CallbackHolder(base::WeakPtr client, Callback callback) : + client_(client), + callback_(std::move(callback)) {} + ~CallbackHolder() = default; + + bool is_valid() { + return !!client_.get(); + } + + Callback& get() { + return callback_; + } + + private: + base::WeakPtr client_; + Callback callback_; + }; + + static void OnInitialize( + CallbackHolder* holder, + const int32_t result); + + static void OnShutdown( + CallbackHolder* holder, + const int32_t result); + + static void OnRemoveAllHistory( + CallbackHolder* holder, + const int32_t result); + std::unique_ptr bat_ads_client_mojo_proxy_; std::unique_ptr ads_; diff --git a/components/services/bat_ads/bat_ads_service_impl.cc b/components/services/bat_ads/bat_ads_service_impl.cc index 2eaec4792a7..1ecacdb97be 100644 --- a/components/services/bat_ads/bat_ads_service_impl.cc +++ b/components/services/bat_ads/bat_ads_service_impl.cc @@ -17,7 +17,7 @@ namespace bat_ads { BatAdsServiceImpl::BatAdsServiceImpl( std::unique_ptr service_ref) : service_ref_(std::move(service_ref)), - has_initialized_(false) {} + is_initialized_(false) {} BatAdsServiceImpl::~BatAdsServiceImpl() {} @@ -27,14 +27,14 @@ void BatAdsServiceImpl::Create( CreateCallback callback) { mojo::MakeStrongAssociatedBinding( std::make_unique(std::move(client_info)), std::move(bat_ads)); - has_initialized_ = true; + is_initialized_ = true; std::move(callback).Run(); } void BatAdsServiceImpl::SetProduction( const bool is_production, SetProductionCallback callback) { - DCHECK(!has_initialized_ || ads::_is_production == is_production); + DCHECK(!is_initialized_ || ads::_is_production == is_production); ads::_is_production = is_production; std::move(callback).Run(); } @@ -42,7 +42,7 @@ void BatAdsServiceImpl::SetProduction( void BatAdsServiceImpl::SetTesting( const bool is_testing, SetTestingCallback callback) { - DCHECK(!has_initialized_ || ads::_is_testing == is_testing); + DCHECK(!is_initialized_ || ads::_is_testing == is_testing); ads::_is_testing = is_testing; std::move(callback).Run(); } @@ -50,16 +50,9 @@ void BatAdsServiceImpl::SetTesting( void BatAdsServiceImpl::SetDebug( const bool is_debug, SetDebugCallback callback) { - DCHECK(!has_initialized_ || ads::_is_debug == is_debug); + DCHECK(!is_initialized_ || ads::_is_debug == is_debug); ads::_is_debug = is_debug; std::move(callback).Run(); } -void BatAdsServiceImpl::IsSupportedRegion( - const std::string& locale, - IsSupportedRegionCallback callback) { - DCHECK(!has_initialized_); - std::move(callback).Run(ads::Ads::IsSupportedRegion(locale)); -} - } // namespace bat_ads diff --git a/components/services/bat_ads/bat_ads_service_impl.h b/components/services/bat_ads/bat_ads_service_impl.h index 3116fe8240a..cc5d115e6f1 100644 --- a/components/services/bat_ads/bat_ads_service_impl.h +++ b/components/services/bat_ads/bat_ads_service_impl.h @@ -41,13 +41,9 @@ class BatAdsServiceImpl : public mojom::BatAdsService { const bool is_debug, SetDebugCallback callback) override; - void IsSupportedRegion( - const std::string& locale, - IsSupportedRegionCallback callback) override; - private: const std::unique_ptr service_ref_; - bool has_initialized_; + bool is_initialized_; DISALLOW_COPY_AND_ASSIGN(BatAdsServiceImpl); }; diff --git a/components/services/bat_ads/public/cpp/ads_client_mojo_bridge.cc b/components/services/bat_ads/public/cpp/ads_client_mojo_bridge.cc index 479fea9905c..ee237f4c91b 100644 --- a/components/services/bat_ads/public/cpp/ads_client_mojo_bridge.cc +++ b/components/services/bat_ads/public/cpp/ads_client_mojo_bridge.cc @@ -102,15 +102,6 @@ void AdsClientMojoBridge::IsNetworkConnectionAvailable( std::move(callback).Run(ads_client_->IsNetworkConnectionAvailable()); } -bool AdsClientMojoBridge::GenerateUUID(std::string* out_uuid) { - *out_uuid = ads_client_->GenerateUUID(); - return true; -} - -void AdsClientMojoBridge::GenerateUUID(GenerateUUIDCallback callback) { - std::move(callback).Run(ads_client_->GenerateUUID()); -} - bool AdsClientMojoBridge::IsNotificationsAvailable(bool* out_available) { *out_available = ads_client_->IsNotificationsAvailable(); return true; @@ -308,6 +299,10 @@ void AdsClientMojoBridge::ShowNotification( ads_client_->ShowNotification(std::move(info)); } +void AdsClientMojoBridge::CloseNotification(const std::string& id) { + ads_client_->CloseNotification(id); +} + void AdsClientMojoBridge::SetCatalogIssuers( const std::string& issuers_info) { auto info = std::make_unique(); diff --git a/components/services/bat_ads/public/cpp/ads_client_mojo_bridge.h b/components/services/bat_ads/public/cpp/ads_client_mojo_bridge.h index 4ac753fe71b..56c4a20cb0e 100644 --- a/components/services/bat_ads/public/cpp/ads_client_mojo_bridge.h +++ b/components/services/bat_ads/public/cpp/ads_client_mojo_bridge.h @@ -40,8 +40,6 @@ class AdsClientMojoBridge : public mojom::BatAdsClient, bool IsNetworkConnectionAvailable(bool* out_available) override; void IsNetworkConnectionAvailable( IsNetworkConnectionAvailableCallback callback) override; - bool GenerateUUID(std::string* out_uuid) override; - void GenerateUUID(GenerateUUIDCallback callback) override; bool IsNotificationsAvailable(bool* out_available) override; void IsNotificationsAvailable( IsNotificationsAvailableCallback callback) override; @@ -73,6 +71,7 @@ class AdsClientMojoBridge : public mojom::BatAdsClient, URLRequestCallback callback) override; void LoadSampleBundle(LoadSampleBundleCallback callback) override; void ShowNotification(const std::string& notification_info) override; + void CloseNotification(const std::string& id) override; void SetCatalogIssuers(const std::string& issuers_info) override; void ConfirmAd(const std::string& notification_info) override; void SaveBundleState(const std::string& bundle_state, diff --git a/components/services/bat_ads/public/interfaces/bat_ads.mojom b/components/services/bat_ads/public/interfaces/bat_ads.mojom index b011a3782c4..cbe1cac8d9e 100644 --- a/components/services/bat_ads/public/interfaces/bat_ads.mojom +++ b/components/services/bat_ads/public/interfaces/bat_ads.mojom @@ -1,6 +1,8 @@ +// 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/. + module bat_ads.mojom; const string kServiceName = "bat_ads"; @@ -8,11 +10,10 @@ const string kServiceName = "bat_ads"; // Service which hands out bat ads. interface BatAdsService { Create(associated BatAdsClient bat_ads_client, - associated BatAds& database) => (); + associated BatAds& database) => (); SetProduction(bool is_production) => (); SetTesting(bool is_testing) => (); SetDebug(bool is_debug) => (); - IsSupportedRegion(string locale) => (bool is_supported); }; interface BatAdsClient { @@ -27,8 +28,6 @@ interface BatAdsClient { [Sync] IsNetworkConnectionAvailable() => (bool available); [Sync] - GenerateUUID() => (string uuid); - [Sync] IsNotificationsAvailable() => (bool available); [Sync] SetTimer(uint64 time_offset) => (uint32 timer_id); @@ -50,9 +49,10 @@ interface BatAdsClient { LoadUserModelForLocale(string locale) => (int32 result, string value); LoadSampleBundle() => (int32 result, string value); URLRequest(string url, array headers, string content, - string content_type, int32 method) => - (int32 status_code, string content, map headers); + string content_type, int32 method) => + (int32 status_code, string content, map headers); ShowNotification(string notification_info); + CloseNotification(string id); SetCatalogIssuers(string issuers_info); ConfirmAd(string notification_info); SaveBundleState(string bundle_state) => (int32 result); @@ -61,9 +61,12 @@ interface BatAdsClient { }; interface BatAds { - Initialize() => (); + Initialize() => (int32 result); + Shutdown() => (int32 result); + SetConfirmationsIsReady(bool is_ready); + ChangeLocale(string locale); ClassifyPage(string url, string page); - TabClosed(int32 tab_id); + ServeSampleAd(); OnTimer(uint32 timer_id); OnUnIdle(); OnIdle(); @@ -71,11 +74,9 @@ interface BatAds { OnBackground(); OnMediaPlaying(int32 tab_id); OnMediaStopped(int32 tab_id); - TabUpdated(int32 tab_id, string url, bool is_active, bool is_incognito); - RemoveAllHistory() => (); - SetConfirmationsIsReady(bool is_ready); - ServeSampleAd(); - GenerateAdReportingNotificationShownEvent(string notification_info); - GenerateAdReportingNotificationResultEvent( - string notification_info, int32 result_type); + OnTabUpdated(int32 tab_id, string url, bool is_active, bool is_incognito); + OnTabClosed(int32 tab_id); + GetNotificationForId(string id) => (string notification_info); + OnNotificationEvent(string id, int32 type); + RemoveAllHistory() => (int32 result); }; diff --git a/vendor/bat-native-ads/BUILD.gn b/vendor/bat-native-ads/BUILD.gn index 4cf01e0a5bd..3ac5963a220 100644 --- a/vendor/bat-native-ads/BUILD.gn +++ b/vendor/bat-native-ads/BUILD.gn @@ -75,8 +75,8 @@ source_set("ads") { "include/bat/ads/export.h", "include/bat/ads/issuer_info.h", "include/bat/ads/issuers_info.h", + "include/bat/ads/notification_event_type.h", "include/bat/ads/notification_info.h", - "include/bat/ads/notification_result_type.h", "include/bat/ads/result.h", "src/bat/ads/ad_info.cc", "src/bat/ads/ads.cc", @@ -129,6 +129,9 @@ source_set("ads") { "src/bat/ads/internal/locale_helper.cc", "src/bat/ads/internal/locale_helper.h", "src/bat/ads/internal/logging.h", + "src/bat/ads/internal/notification_result_type.h", + "src/bat/ads/internal/notifications.cc", + "src/bat/ads/internal/notifications.h", "src/bat/ads/internal/search_provider_info.cc", "src/bat/ads/internal/search_provider_info.h", "src/bat/ads/internal/search_providers.cc", diff --git a/vendor/bat-native-ads/README.md b/vendor/bat-native-ads/README.md index 850f5d6e384..1289b909e2f 100644 --- a/vendor/bat-native-ads/README.md +++ b/vendor/bat-native-ads/README.md @@ -24,116 +24,124 @@ bundle-schema.json ### Native -Initialize Ads by calling `Initialize` when Ads are enabled or disabled on the Client as follows: +`IsSupportedRegion` should be called to determine if ads are supported for the specified region +``` +static bool IsSupportedRegion( + const std::string& locale) +``` +Initialize ads by calling `Initialize` ``` -void Initialize() +void Initialize( + InitializeCallback callback) ``` -`IsSupportedRegion` should be called to determine if Ads are supported for the specified region +Shutdown ads by calling `Shutdown` ``` -static bool IsSupportedRegion( - const std::string& locale) +void Shutdown( + ShutdownCallback callback) ``` -`OnForeground` should be called when the browser enters the foreground +`SetConfirmationsIsReady` should be called to inform ads if Confirmations is ready ``` -void OnForeground() +void SetConfirmationsIsReady( + const bool is_ready) ``` -`OnBackground` should be called when the browser enters the background +`ChangeLocale` should be called when the user changes the operating system's locale, i.e. `en`, `en_US` or `en_GB.UTF-8`. This call is not required if the operating system restarts the app when the user changes their locale ``` -void OnBackground() +void ChangeLocale( + const std::string& locale) ``` -`OnIdle` should be called periodically on desktop browsers as set by `SetIdleThreshold` to record when the browser is idle. This call is optional for mobile devices +`ClassifyPage` should be called when a page has loaded in the current browser tab, and the HTML is available for analysis ``` -void OnIdle() +void ClassifyPage( + const std::string& url, + const std::string& html) ``` -`OnUnidle` should be called periodically on desktop browsers as set by `SetIdleThreshold` to record when the browser is no longer idle. This call is optional for mobile devices +`ServeSampleAd` should be called when the user invokes "Show Sample Ad" on the Client; a notification is then sent to the Client for processing ``` -void OnUnIdle() +void ServeSampleAd() ``` -`OnMediaPlaying` should be called to record when a tab has started playing media (A/V) +`OnTimer` should be called when a timer is triggered ``` -void OnMediaPlaying( - const int32_t tab_id) +void OnTimer( + const uint32_t timer_id) ``` -`OnMediaStopped` should be called to record when a tab has stopped playing media (A/V) +`OnUnidle` should be called periodically on desktop browsers as set by `SetIdleThreshold` to record when the browser is no longer idle. This call is optional for mobile devices ``` -void OnMediaStopped( - const int32_t tab_id) +void OnUnIdle() ``` -`TabUpdated` should be called to record user activity on a browser tab +`OnIdle` should be called periodically on desktop browsers as set by `SetIdleThreshold` to record when the browser is idle. This call is optional for mobile devices ``` -void TabUpdated( - const int32_t tab_id, - const std::string& url, - const bool is_active, - const bool is_incognito) +void OnIdle() ``` -`TabClosed` should be called to record when a browser tab is closed +`OnForeground` should be called when the browser enters the foreground ``` -void TabClosed( - const int32_t tab_id) +void OnForeground() ``` -`RemoveAllHistory` should be called to remove all cached history when the user clears browsing data +`OnBackground` should be called when the browser enters the background ``` -void RemoveAllHistory() +void OnBackground() ``` -`SetConfirmationsIsReady` should be called to inform Ads if Confirmations is ready +`OnMediaPlaying` should be called to record when a tab has started playing media (A/V) ``` -void SetConfirmationsIsReady( - const bool is_ready) +void OnMediaPlaying( + const int32_t tab_id) ``` -`ChangeLocale` should be called when the user changes the operating system's locale, i.e. `en`, `en_US` or `en_GB.UTF-8`. This call is not required if the operating system restarts the app when the user changes their locale +`OnMediaStopped` should be called to record when a tab has stopped playing media (A/V) ``` -void ChangeLocale( - const std::string& locale) +void OnMediaStopped( + const int32_t tab_id) ``` -`ClassifyPage` should be called when a page has loaded in the current browser tab, and the HTML is available for analysis +`OnTabUpdated` should be called to record user activity on a browser tab ``` -void ClassifyPage( +void OnTabUpdated( + const int32_t tab_id, const std::string& url, - const std::string& html) + const bool is_active, + const bool is_incognito) ``` -`ServeSampleAd` should be called when the user invokes "Show Sample Ad" on the Client; a notification is then sent to the Client for processing +`OnTabClosed` should be called to record when a browser tab is closed ``` -void ServeSampleAd() +void OnTabClosed( + const int32_t tab_id) ``` -`OnTimer` should be called when a timer is triggered +`GetNotificationForId` should return `true` and the notification for the specified id exists ``` -void OnTimer( - const uint32_t timer_id) +bool GetNotificationForId( + const std::string id, + GetNotificationForIdCallback callback) ``` -`GenerateAdReportingNotificationShownEvent` should be called when a notification has been shown +`OnNotificationEvent` should be called when a notifcation event is triggered ``` -void GenerateAdReportingNotificationShownEvent( - const NotificationInfo& info) +void OnNotificationEvent( + const std::string id, + const NotificationActionType type) ``` -`GenerateAdReportingNotificationResultEvent` should be called when a notification has been clicked, dismissed or times out on the Client. Dismiss events for local Notifications may not be available for every version of Android, making the Dismiss notification capture optional for Android devices +`RemoveAllHistory` should be called to remove all cached history when the user clears browsing data ``` -void GenerateAdReportingNotificationResultEvent( - const NotificationInfo& info, - const NotificationResultInfoResultType type) +void RemoveAllHistory( + RemoveAllHistoryCallback callback) ``` ### Client -`IsAdsEnabled` should return `true` if Ads are enabled otherwise returns `false` +`IsAdsEnabled` should return `true` if ads are enabled otherwise returns `false` ``` bool IsAdsEnabled() const ``` @@ -143,12 +151,12 @@ bool IsAdsEnabled() const std::string GetAdsLocale() const ``` -`GetAdsPerHour` should return the number of Ads that can be shown per hour +`GetAdsPerHour` should return the number of ads that can be shown per hour ``` uint64_t GetAdsPerHour() const ``` -`GetAdsPerDay` should return the number of Ads that can be shown per day +`GetAdsPerDay` should return the number of ads that can be shown per day ``` uint64_t GetAdsPerDay() const ``` @@ -182,11 +190,6 @@ void LoadUserModelForLocale( OnLoadCallback callback) const ``` -`GenerateUUID` should generate and return a v4 UUID -``` -const std::string GenerateUUID() const -``` - `IsForeground` should return `true` if the browser is in the foreground otherwise returns `false` ``` bool IsForeground() const @@ -199,27 +202,38 @@ bool IsNotificationsAvailable() const `ShowNotification` should show a notification ``` -void ShowNotification(std::unique_ptr info) +void ShowNotification( + std::unique_ptr info) +``` + +`CloseNotification` should close a notification +``` +void CloseNotification( + const std::string& id) ``` `SetCatalogIssuers` should notify that the catalog issuers have changed ``` - void SetCatalogIssuers(std::unique_ptr info) + void SetCatalogIssuers( + std::unique_ptr info) ``` `ConfirmAd` should be called to inform Confirmations that an Ad was clicked, viewed, dismissed or landed ``` -void ConfirmAd(std::unique_ptr info) +void ConfirmAd( + std::unique_ptr info) ``` `SetTimer` should create a timer to trigger after the time offset specified in seconds. If the timer was created successfully a unique identifier should be returned, otherwise returns `0` ``` -uint32_t SetTimer(const uint64_t time_offset) +uint32_t SetTimer( + const uint64_t time_offset) ``` `KillTimer` should destroy the timer associated with the specified timer identifier ``` -void KillTimer(uint32_t timer_id) +void KillTimer( + uint32_t timer_id) ``` `URLRequest` should start a URL request @@ -250,25 +264,31 @@ void SaveBundleState( `Load` should load a value from persistent storage ``` -void Load(const std::string& name, OnLoadCallback callback) +void Load( + const std::string& name, + OnLoadCallback callback) ``` `LoadJsonSchema` should load a JSON schema from persistent storage, see [resources](#resources) ``` -const std::string LoadJsonSchema(const std::string& name) +const std::string LoadJsonSchema( + const std::string& name) ``` `LoadSampleBundle` should load the sample bundle from persistent storage ``` -void LoadSampleBundle(OnLoadSampleBundleCallback callback) +void LoadSampleBundle( + OnLoadSampleBundleCallback callback) ``` `Reset` should reset a previously saved value, i.e. remove the file from persistent storage ``` -void Reset(const std::string& name, OnResetCallback callback) +void Reset( + const std::string& name, + OnResetCallback callback) ``` -`GetAds` should get Ads for the specified category from the previously persisted bundle state +`GetAds` should get ads for the specified category from the previously persisted bundle state ``` void GetAds( const std::string& category, @@ -277,7 +297,8 @@ void GetAds( `EventLog` should log an event to persistent storage ``` -void EventLog(const std::string& json) +void EventLog( + const std::string& json) ``` `Log` should log diagnostic information to the console diff --git a/vendor/bat-native-ads/include/bat/ads/ads.h b/vendor/bat-native-ads/include/bat/ads/ads.h index d3ec9c43c9a..02264658fa1 100644 --- a/vendor/bat-native-ads/include/bat/ads/ads.h +++ b/vendor/bat-native-ads/include/bat/ads/ads.h @@ -7,10 +7,11 @@ #define BAT_ADS_ADS_H_ #include +#include #include "bat/ads/ads_client.h" #include "bat/ads/export.h" -#include "bat/ads/notification_result_type.h" +#include "bat/ads/notification_event_type.h" #include "bat/ads/notification_info.h" namespace ads { @@ -31,6 +32,12 @@ extern const char _catalog_schema_name[]; extern const char _catalog_name[]; extern const char _client_name[]; +using InitializeCallback = std::function; +using ShutdownCallback = std::function; +using GetNotificationForIdCallback = + std::function)>; +using RemoveAllHistoryCallback = std::function; + class ADS_EXPORT Ads { public: Ads() = default; @@ -41,25 +48,48 @@ class ADS_EXPORT Ads { // Should be called to determine if Ads are supported for the specified locale static bool IsSupportedRegion(const std::string& locale); - // Should be called when Ads are enabled or disabled on the Client - virtual void Initialize() = 0; + // Should be called when Ads is enabled on the Client + virtual void Initialize(InitializeCallback callback) = 0; - // Should be called when the browser enters the foreground - virtual void OnForeground() = 0; + // Should be called when Ads is disabled on the Client + virtual void Shutdown(ShutdownCallback callback) = 0; - // Should be called when the browser enters the background - virtual void OnBackground() = 0; + // Should be called to inform Ads if Confirmations is ready + virtual void SetConfirmationsIsReady(const bool is_ready) = 0; - // Should be called periodically on desktop browsers as set by - // SetIdleThreshold to record when the browser is idle. This call is optional - // for mobile devices - virtual void OnIdle() = 0; + // Should be called when the user changes the operating system's locale, i.e. + // en, en_US or en_GB.UTF-8 unless the operating system restarts the app + virtual void ChangeLocale(const std::string& locale) = 0; + + // Should be called when a page has loaded in the current browser tab, and the + // HTML is available for analysis + virtual void ClassifyPage( + const std::string& url, + const std::string& html) = 0; + + // Should be called when the user invokes "Show Sample Ad" on the Client; a + // Notification is then sent to the Client for processing + virtual void ServeSampleAd() = 0; + + // Should be called when a timer is triggered + virtual void OnTimer(const uint32_t timer_id) = 0; // Should be called periodically on desktop browsers as set by // SetIdleThreshold to record when the browser is no longer idle. This call is // optional for mobile devices virtual void OnUnIdle() = 0; + // Should be called periodically on desktop browsers as set by + // SetIdleThreshold to record when the browser is idle. This call is optional + // for mobile devices + virtual void OnIdle() = 0; + + // Should be called when the browser enters the foreground + virtual void OnForeground() = 0; + + // Should be called when the browser enters the background + virtual void OnBackground() = 0; + // Should be called to record when a tab has started playing media (A/V) virtual void OnMediaPlaying(const int32_t tab_id) = 0; @@ -67,49 +97,27 @@ class ADS_EXPORT Ads { virtual void OnMediaStopped(const int32_t tab_id) = 0; // Should be called to record user activity on a browser tab - virtual void TabUpdated( + virtual void OnTabUpdated( const int32_t tab_id, const std::string& url, const bool is_active, const bool is_incognito) = 0; // Should be called to record when a browser tab is closed - virtual void TabClosed(const int32_t tab_id) = 0; + virtual void OnTabClosed(const int32_t tab_id) = 0; - // Should be called to remove all cached history - virtual void RemoveAllHistory() = 0; - - // Should be called to inform Ads if Confirmations is ready - virtual void SetConfirmationsIsReady(const bool is_ready) = 0; + // Should return true and the notification for the specified id exists + virtual bool GetNotificationForId( + const std::string& id, + ads::NotificationInfo* notification) = 0; - // Should be called when the user changes the operating system's locale, i.e. - // en, en_US or en_GB.UTF-8 unless the operating system restarts the app - virtual void ChangeLocale(const std::string& locale) = 0; + // Should be called when a notification event is triggered + virtual void OnNotificationEvent( + const std::string& id, + const ads::NotificationEventType type) = 0; - // Should be called when a page has loaded in the current browser tab, and the - // HTML is available for analysis - virtual void ClassifyPage( - const std::string& url, - const std::string& html) = 0; - - // Should be called when the user invokes "Show Sample Ad" on the Client; a - // Notification is then sent to the Client for processing - virtual void ServeSampleAd() = 0; - - // Should be called when a timer is triggered - virtual void OnTimer(const uint32_t timer_id) = 0; - - // Should be called when a Notification has been shown - virtual void GenerateAdReportingNotificationShownEvent( - const NotificationInfo& info) = 0; - - // Should be called when a Notification has been clicked, dismissed or times - // out on the Client. Dismiss events for local Notifications may not be - // available for every version of Android, making the Dismiss notification - // capture optional for Android on 100% of devices - virtual void GenerateAdReportingNotificationResultEvent( - const NotificationInfo& info, - const NotificationResultInfoResultType type) = 0; + // Should be called to remove all cached history + virtual void RemoveAllHistory(RemoveAllHistoryCallback callback) = 0; private: // Not copyable, not assignable diff --git a/vendor/bat-native-ads/include/bat/ads/ads_client.h b/vendor/bat-native-ads/include/bat/ads/ads_client.h index 8b5b792327a..b79e659943b 100644 --- a/vendor/bat-native-ads/include/bat/ads/ads_client.h +++ b/vendor/bat-native-ads/include/bat/ads/ads_client.h @@ -55,7 +55,7 @@ using OnLoadSampleBundleCallback = std::function; using URLRequestCallback = std::function& headers)>; + const std::map&)>; class ADS_EXPORT AdsClient { public: @@ -93,9 +93,6 @@ class ADS_EXPORT AdsClient { const std::string& locale, OnLoadCallback callback) const = 0; - // Should generate return a v4 UUID - virtual const std::string GenerateUUID() const = 0; - // Should return true if the browser is in the foreground otherwise returns // false virtual bool IsForeground() const = 0; @@ -107,6 +104,9 @@ class ADS_EXPORT AdsClient { // Should show a notification virtual void ShowNotification(std::unique_ptr info) = 0; + // Should close a notification + virtual void CloseNotification(const std::string& id) = 0; + // Should notify that the catalog issuers have changed virtual void SetCatalogIssuers(std::unique_ptr info) = 0; diff --git a/vendor/bat-native-ads/include/bat/ads/notification_event_type.h b/vendor/bat-native-ads/include/bat/ads/notification_event_type.h new file mode 100644 index 00000000000..13f09c892ae --- /dev/null +++ b/vendor/bat-native-ads/include/bat/ads/notification_event_type.h @@ -0,0 +1,20 @@ +/* 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 BAT_ADS_NOTIFICATION_EVENT_TYPE_H_ +#define BAT_ADS_NOTIFICATION_EVENT_TYPE_H_ + +namespace ads { + +enum class NotificationEventType { + VIEWED, + CLICKED, + DISMISSED, + TIMEOUT +}; + +} // namespace ads + +#endif // BAT_ADS_NOTIFICATION_EVENT_TYPE_H_ diff --git a/vendor/bat-native-ads/include/bat/ads/notification_info.h b/vendor/bat-native-ads/include/bat/ads/notification_info.h index 16d2f49fcbb..cabe9075a23 100644 --- a/vendor/bat-native-ads/include/bat/ads/notification_info.h +++ b/vendor/bat-native-ads/include/bat/ads/notification_info.h @@ -16,7 +16,7 @@ namespace ads { struct ADS_EXPORT NotificationInfo { NotificationInfo(); - explicit NotificationInfo(const NotificationInfo& info); + NotificationInfo(const NotificationInfo& info); ~NotificationInfo(); const std::string ToJson() const; @@ -24,6 +24,7 @@ struct ADS_EXPORT NotificationInfo { const std::string& json, std::string* error_description = nullptr); + std::string id; std::string creative_set_id; std::string category; std::string advertiser; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ads_client_mock.h b/vendor/bat-native-ads/src/bat/ads/internal/ads_client_mock.h index 46735cce76c..5c30a4c1a86 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ads_client_mock.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/ads_client_mock.h @@ -62,8 +62,6 @@ class MockAdsClient : public AdsClient { const std::string& locale, OnLoadCallback callback)); - MOCK_CONST_METHOD0(GenerateUUID, const std::string()); - MOCK_CONST_METHOD0(IsForeground, bool()); MOCK_CONST_METHOD0(IsNotificationsAvailable, bool()); @@ -71,6 +69,9 @@ class MockAdsClient : public AdsClient { MOCK_METHOD1(ShowNotification, void( std::unique_ptr info)); + MOCK_METHOD1(CloseNotification, void( + const std::string& id)); + MOCK_METHOD1(SetCatalogIssuers, void( std::unique_ptr info)); diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ads_impl.cc b/vendor/bat-native-ads/src/bat/ads/internal/ads_impl.cc index 88306b501ad..886bb792825 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ads_impl.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ads_impl.cc @@ -29,6 +29,8 @@ #include "base/strings/string_util.h" #include "base/strings/string_split.h" #include "base/time/time.h" +#include "base/guid.h" + #include "url/gurl.h" using std::placeholders::_1; @@ -54,6 +56,7 @@ AdsImpl::AdsImpl(AdsClient* ads_client) : client_(std::make_unique(this, ads_client)), bundle_(std::make_unique(this, ads_client)), ads_serve_(std::make_unique(this, ads_client, bundle_.get())), + notifications_(std::make_unique(this, ads_client)), user_model_(nullptr), is_initialized_(false), is_confirmations_ready_(false), @@ -62,67 +65,102 @@ AdsImpl::AdsImpl(AdsClient* ads_client) : AdsImpl::~AdsImpl() = default; -void AdsImpl::Initialize() { - if (!ads_client_->IsAdsEnabled()) { - BLOG(INFO) << "Deinitializing as Ads are disabled"; +void AdsImpl::Initialize(InitializeCallback callback) { + initialize_callback_ = callback; - Deinitialize(); + if (IsInitialized()) { + BLOG(INFO) << "Already initialized"; + + initialize_callback_(FAILED); return; } - if (IsInitialized()) { - BLOG(INFO) << "Already initialized"; + auto initialize_step_2_callback = + std::bind(&AdsImpl::InitializeStep2, this, _1); + client_->Initialize(initialize_step_2_callback); +} +void AdsImpl::InitializeStep2(const Result result) { + if (result != SUCCESS) { + initialize_callback_(FAILED); return; } - client_->LoadState(); + auto initialize_step_3_callback = + std::bind(&AdsImpl::InitializeStep3, this, _1); + notifications_->Initialize(initialize_step_3_callback); } -void AdsImpl::InitializeStep2() { +void AdsImpl::InitializeStep3(const Result result) { + if (result != SUCCESS) { + initialize_callback_(FAILED); + return; + } + client_->SetLocales(ads_client_->GetLocales()); LoadUserModel(); } -void AdsImpl::InitializeStep3() { +void AdsImpl::InitializeStep4() { is_initialized_ = true; BLOG(INFO) << "Successfully initialized"; + initialize_callback_(SUCCESS); + is_foreground_ = ads_client_->IsForeground(); ads_client_->SetIdleThreshold(kIdleThresholdInSeconds); NotificationAllowedCheck(false); + client_->UpdateAdUUID(); + if (IsMobile()) { StartDeliveringNotifications(); } - ConfirmAdUUIDIfAdEnabled(); + if (_is_debug) { + StartCollectingActivity(kDebugOneHourInSeconds); + } else { + StartCollectingActivity(base::Time::kSecondsPerHour); + } ads_serve_->DownloadCatalog(); } -void AdsImpl::Deinitialize() { +bool AdsImpl::IsInitialized() { + if (!is_initialized_ || + !ads_client_->IsAdsEnabled() || + !user_model_->IsInitialized()) { + return false; + } + + return true; +} + +void AdsImpl::Shutdown(ShutdownCallback callback) { if (!is_initialized_) { - BLOG(WARNING) << "Failed to deinitialize as not initialized"; + BLOG(WARNING) << "Failed to shutdown as not initialized"; + callback(FAILED); return; } - BLOG(INFO) << "Deinitializing"; + BLOG(INFO) << "Shutting down"; + StopCollectingActivity(); ads_serve_->Reset(); StopDeliveringNotifications(); + notifications_->RemoveAll(); StopSustainingAdInteraction(); last_sustaining_ad_url_ = ""; - RemoveAllHistory(); + client_->RemoveAllHistory(); bundle_->Reset(); user_model_.reset(); @@ -134,16 +172,10 @@ void AdsImpl::Deinitialize() { is_first_run_ = true; is_initialized_ = false; is_foreground_ = false; -} -bool AdsImpl::IsInitialized() { - if (!is_initialized_ || - !ads_client_->IsAdsEnabled() || - !user_model_->IsInitialized()) { - return false; - } + BLOG(INFO) << "Shutdown"; - return true; + callback(SUCCESS); } void AdsImpl::LoadUserModel() { @@ -164,13 +196,11 @@ void AdsImpl::OnUserModelLoaded(const Result result, const std::string& json) { InitializeUserModel(json); if (!IsInitialized()) { - InitializeStep3(); + InitializeStep4(); } } void AdsImpl::InitializeUserModel(const std::string& json) { - // TODO(Terry Mancey): Refactor function to use callbacks - BLOG(INFO) << "Initializing user model"; user_model_.reset(usermodel::UserModel::CreateInstance()); @@ -190,6 +220,12 @@ bool AdsImpl::IsMobile() const { return true; } +bool AdsImpl::GetNotificationForId( + const std::string& id, + ads::NotificationInfo* notification) { + return notifications_->Get(id, notification); +} + void AdsImpl::OnForeground() { is_foreground_ = true; GenerateAdReportingForegroundEvent(); @@ -260,6 +296,76 @@ bool AdsImpl::IsMediaPlaying() const { return true; } +void AdsImpl::OnNotificationEvent( + const std::string& id, + const ads::NotificationEventType type) { + NotificationInfo notification; + if (!notifications_->Get(id, ¬ification)) { + return; + } + + switch (type) { + case ads::NotificationEventType::VIEWED: { + NotificationEventViewed(id, notification); + break; + } + + case ads::NotificationEventType::CLICKED: { + NotificationEventClicked(id, notification); + break; + } + + case ads::NotificationEventType::DISMISSED: { + NotificationEventDismissed(id, notification); + break; + } + + case ads::NotificationEventType::TIMEOUT: { + NotificationEventTimedOut(id, notification); + break; + } + } +} + +void AdsImpl::NotificationEventViewed( + const std::string& id, + const NotificationInfo& notification) { + GenerateAdReportingNotificationShownEvent(notification); + + ConfirmAd(notification, ConfirmationType::VIEW); +} + +void AdsImpl::NotificationEventClicked( + const std::string& id, + const NotificationInfo& notification) { + notifications_->Remove(id); + + GenerateAdReportingNotificationResultEvent(notification, + NotificationResultInfoResultType::CLICKED); + + ConfirmAd(notification, ConfirmationType::CLICK); +} + +void AdsImpl::NotificationEventDismissed( + const std::string& id, + const NotificationInfo& notification) { + notifications_->Remove(id); + + GenerateAdReportingNotificationResultEvent(notification, + NotificationResultInfoResultType::DISMISSED); + + ConfirmAd(notification, ConfirmationType::DISMISS); +} + +void AdsImpl::NotificationEventTimedOut( + const std::string& id, + const NotificationInfo& notification) { + notifications_->Remove(id); + + GenerateAdReportingNotificationResultEvent(notification, + NotificationResultInfoResultType::TIMEOUT); +} + bool AdsImpl::IsDoNotDisturb() const { if (!IsMobile()) { return false; @@ -277,7 +383,7 @@ bool AdsImpl::IsDoNotDisturb() const { return true; } -void AdsImpl::TabUpdated( +void AdsImpl::OnTabUpdated( const int32_t tab_id, const std::string& url, const bool is_active, @@ -289,7 +395,7 @@ void AdsImpl::TabUpdated( client_->UpdateLastUserActivity(); if (is_active) { - BLOG(INFO) << "TabUpdated.IsFocused for tab id: " << tab_id + BLOG(INFO) << "OnTabUpdated.IsFocused for tab id: " << tab_id << " and url: " << url; last_shown_tab_id_ = tab_id; @@ -303,7 +409,7 @@ void AdsImpl::TabUpdated( focus_info.tab_id = tab_id; GenerateAdReportingFocusEvent(focus_info); } else { - BLOG(INFO) << "TabUpdated.IsBlurred for tab id: " << tab_id + BLOG(INFO) << "OnTabUpdated.IsBlurred for tab id: " << tab_id << " and url: " << url; BlurInfo blur_info; @@ -312,8 +418,8 @@ void AdsImpl::TabUpdated( } } -void AdsImpl::TabClosed(const int32_t tab_id) { - BLOG(INFO) << "TabClosed for tab id: " << tab_id; +void AdsImpl::OnTabClosed(const int32_t tab_id) { + BLOG(INFO) << "OnTabClosed for tab id: " << tab_id; OnMediaStopped(tab_id); @@ -322,25 +428,10 @@ void AdsImpl::TabClosed(const int32_t tab_id) { GenerateAdReportingDestroyEvent(destroy_info); } -void AdsImpl::RemoveAllHistory() { +void AdsImpl::RemoveAllHistory(RemoveAllHistoryCallback callback) { client_->RemoveAllHistory(); - ConfirmAdUUIDIfAdEnabled(); -} - -void AdsImpl::ConfirmAdUUIDIfAdEnabled() { - if (!ads_client_->IsAdsEnabled()) { - StopCollectingActivity(); - return; - } - - client_->UpdateAdUUID(); - - if (_is_debug) { - StartCollectingActivity(kDebugOneHourInSeconds); - } else { - StartCollectingActivity(base::Time::kSecondsPerHour); - } + callback(SUCCESS); } void AdsImpl::SetConfirmationsIsReady(const bool is_ready) { @@ -356,7 +447,7 @@ void AdsImpl::ChangeLocale(const std::string& locale) { auto locales = ads_client_->GetLocales(); if (std::find(locales.begin(), locales.end(), locale) != locales.end()) { - BLOG(INFO) << "Change Localed to " << locale; + BLOG(INFO) << "Change locale to " << locale; client_->SetLocale(locale); } else { std::string closest_match_for_locale = ""; @@ -368,7 +459,7 @@ void AdsImpl::ChangeLocale(const std::string& locale) { closest_match_for_locale = kDefaultLanguageCode; } - BLOG(INFO) << "Locale not found, so changed Locale to closest match: " + BLOG(INFO) << "Locale not found, so changed locale to closest match: " << closest_match_for_locale; client_->SetLocale(closest_match_for_locale); } @@ -736,8 +827,8 @@ void AdsImpl::OnGetAds( auto ads_unseen = GetUnseenAds(ads); - BLOG(INFO) << "Found " << ads_unseen.size() << " out of " - << ads.size() << " ads for \"" << category << "\" category"; + BLOG(INFO) << "Found " << ads_unseen.size() << " out of " << ads.size() + << " unseen ads for \"" << category << "\" category"; if (ads_unseen.empty()) { // TODO(Terry Mancey): Implement Log (#44) @@ -760,40 +851,22 @@ std::vector AdsImpl::GetUnseenAds( std::vector ads_unseen = {}; for (const auto& ad : ads) { - std::deque creative_set = {}; - auto creative_set_history = client_->GetCreativeSetHistory(); - if (creative_set_history.find(ad.creative_set_id) - != creative_set_history.end()) { - creative_set = creative_set_history.at(ad.creative_set_id); - } - - if (creative_set.size() >= ad.total_max) { - BLOG(WARNING) << "creativeSetId " << ad.creative_set_id + if (!AdRespectsTotalMaxFrequencyCapping(ad)) { + BLOG(INFO) << "creativeSetId " << ad.creative_set_id << " has exceeded the totalMax"; continue; } - auto day_window = base::Time::kSecondsPerHour * base::Time::kHoursPerDay; - - if (!HistoryRespectsRollingTimeConstraint( - creative_set, day_window, ad.per_day)) { - BLOG(WARNING) << "creativeSetId " << ad.creative_set_id + if (!AdRespectsPerDayFrequencyCapping(ad)) { + BLOG(INFO) << "creativeSetId " << ad.creative_set_id << " has exceeded the perDay"; continue; } - std::deque campaign = {}; - auto campaign_history = client_->GetCampaignHistory(); - if (campaign_history.find(ad.campaign_id) - != campaign_history.end()) { - campaign = campaign_history.at(ad.campaign_id); - } - - if (!HistoryRespectsRollingTimeConstraint( - campaign, day_window, ad.daily_cap)) { - BLOG(WARNING) << "creativeSetId " << ad.creative_set_id + if (!AdRespectsDailyCapFrequencyCapping(ad)) { + BLOG(INFO) << "creativeSetId " << ad.creative_set_id << " has exceeded the dailyCap"; continue; @@ -805,6 +878,53 @@ std::vector AdsImpl::GetUnseenAds( return ads_unseen; } +bool AdsImpl::AdRespectsTotalMaxFrequencyCapping(const AdInfo& ad) { + auto creative_set = GetCreativeSetForId(ad.creative_set_id); + if (creative_set.size() >= ad.total_max) { + return false; + } + + return true; +} + +bool AdsImpl::AdRespectsPerDayFrequencyCapping(const AdInfo& ad) { + auto creative_set = GetCreativeSetForId(ad.creative_set_id); + auto day_window = base::Time::kSecondsPerHour * base::Time::kHoursPerDay; + + return HistoryRespectsRollingTimeConstraint( + creative_set, day_window, ad.per_day); +} + +bool AdsImpl::AdRespectsDailyCapFrequencyCapping(const AdInfo& ad) { + auto campaign = GetCampaignForId(ad.campaign_id); + auto day_window = base::Time::kSecondsPerHour * base::Time::kHoursPerDay; + + return HistoryRespectsRollingTimeConstraint( + campaign, day_window, ad.daily_cap); +} + +std::deque AdsImpl::GetCreativeSetForId(const std::string& id) { + std::deque creative_set = {}; + + auto creative_set_history = client_->GetCreativeSetHistory(); + if (creative_set_history.find(id) != creative_set_history.end()) { + creative_set = creative_set_history.at(id); + } + + return creative_set; +} + +std::deque AdsImpl::GetCampaignForId(const std::string& id) { + std::deque campaign = {}; + + auto campaign_history = client_->GetCampaignHistory(); + if (campaign_history.find(id) != campaign_history.end()) { + campaign = campaign_history.at(id); + } + + return campaign; +} + bool AdsImpl::IsAdValid(const AdInfo& ad_info) { if (ad_info.advertiser.empty() || ad_info.notification_text.empty() || @@ -835,6 +955,7 @@ bool AdsImpl::ShowAd( } auto notification_info = std::make_unique(); + notification_info->id = base::GenerateGUID(); notification_info->advertiser = ad_info.advertiser; notification_info->category = category; notification_info->text = ad_info.notification_text; @@ -847,14 +968,16 @@ bool AdsImpl::ShowAd( // notificationUrl, notificationText, advertiser, uuid, hierarchy} BLOG(INFO) << "Notification shown:" + << std::endl << " id: " << notification_info->id << std::endl << " campaign_id: " << ad_info.campaign_id - << std::endl << " category: " << category << std::endl << " winnerOverTime: " << GetWinnerOverTimeCategory() - << std::endl << " notificationUrl: " << notification_info->url - << std::endl << " notificationText: " << notification_info->text << std::endl << " advertiser: " << notification_info->advertiser + << std::endl << " category: " << notification_info->category + << std::endl << " notificationText: " << notification_info->text + << std::endl << " notificationUrl: " << notification_info->url << std::endl << " uuid: " << notification_info->uuid; + notifications_->Add(*notification_info); ads_client_->ShowNotification(std::move(notification_info)); client_->AppendCurrentTimeToAdsShownHistory(); @@ -1223,8 +1346,8 @@ void AdsImpl::GenerateAdReportingNotificationShownEvent( writer.String("notificationClassification"); writer.StartArray(); - std::vector classifications = base::SplitString(info.category, - "-", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); + std::vector classifications = base::SplitString( + info.category, "-", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); for (const auto& classification : classifications) { writer.String(classification.c_str()); } @@ -1246,8 +1369,6 @@ void AdsImpl::GenerateAdReportingNotificationShownEvent( auto* json = buffer.GetString(); ads_client_->EventLog(json); - - ConfirmAd(info, ConfirmationType::VIEW); } void AdsImpl::GenerateAdReportingNotificationResultEvent( @@ -1301,8 +1422,8 @@ void AdsImpl::GenerateAdReportingNotificationResultEvent( writer.String("notificationClassification"); writer.StartArray(); - std::vector classifications = base::SplitString(info.category, - "-", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); + std::vector classifications = base::SplitString( + info.category, "-", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); for (const auto& classification : classifications) { writer.String(classification.c_str()); } @@ -1324,22 +1445,6 @@ void AdsImpl::GenerateAdReportingNotificationResultEvent( auto* json = buffer.GetString(); ads_client_->EventLog(json); - - switch (type) { - case NotificationResultInfoResultType::CLICKED: { - ConfirmAd(info, ConfirmationType::CLICK); - break; - } - - case NotificationResultInfoResultType::DISMISSED: { - ConfirmAd(info, ConfirmationType::DISMISS); - break; - } - - case NotificationResultInfoResultType::TIMEOUT: { - break; - } - } } void AdsImpl::GenerateAdReportingConfirmationEvent( diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ads_impl.h b/vendor/bat-native-ads/src/bat/ads/internal/ads_impl.h index 875bf3f272d..c0c87ef0661 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ads_impl.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/ads_impl.h @@ -15,7 +15,7 @@ #include "bat/ads/ads.h" #include "bat/ads/ad_info.h" -#include "bat/ads/notification_result_type.h" +#include "bat/ads/notification_event_type.h" #include "bat/ads/notification_info.h" #include "bat/ads/internal/ads_serve.h" @@ -23,8 +23,10 @@ #include "bat/ads/internal/event_type_destroy_info.h" #include "bat/ads/internal/event_type_focus_info.h" #include "bat/ads/internal/event_type_load_info.h" +#include "bat/ads/internal/notification_result_type.h" #include "bat/ads/internal/client.h" #include "bat/ads/internal/bundle.h" +#include "bat/ads/internal/notifications.h" #include "bat/usermodel/user_model.h" @@ -33,6 +35,7 @@ namespace ads { class Client; class Bundle; class AdsServe; +class Notifications; class AdsImpl : public Ads { public: @@ -41,12 +44,15 @@ class AdsImpl : public Ads { bool is_first_run_; - void Initialize() override; - void InitializeStep2(); - void InitializeStep3(); - void Deinitialize(); + InitializeCallback initialize_callback_; + void Initialize(InitializeCallback callback) override; + void InitializeStep2(const Result result); + void InitializeStep3(const Result result); + void InitializeStep4(); bool IsInitialized(); + void Shutdown(ShutdownCallback callback) override; + void LoadUserModel(); void OnUserModelLoaded(const Result result, const std::string& json); void InitializeUserModel(const std::string& json); @@ -66,21 +72,39 @@ class AdsImpl : public Ads { void OnMediaStopped(const int32_t tab_id) override; bool IsMediaPlaying() const; + bool GetNotificationForId( + const std::string& id, + ads::NotificationInfo* notification) override; + + void OnNotificationEvent( + const std::string& id, + const ads::NotificationEventType type) override; + void NotificationEventViewed( + const std::string& id, + const NotificationInfo& notification); + void NotificationEventClicked( + const std::string& id, + const NotificationInfo& notification); + void NotificationEventDismissed( + const std::string& id, + const NotificationInfo& notification); + void NotificationEventTimedOut( + const std::string& id, + const NotificationInfo& notification); + bool IsDoNotDisturb() const; int32_t last_shown_tab_id_; std::string last_shown_tab_url_; std::string previous_tab_url_; - void TabUpdated( + void OnTabUpdated( const int32_t tab_id, const std::string& url, const bool is_active, const bool is_incognito) override; - void TabClosed(const int32_t tab_id) override; - - void RemoveAllHistory() override; + void OnTabClosed(const int32_t tab_id) override; - void ConfirmAdUUIDIfAdEnabled(); + void RemoveAllHistory(RemoveAllHistoryCallback callback) override; void SetConfirmationsIsReady(const bool is_ready) override; @@ -112,6 +136,12 @@ class AdsImpl : public Ads { const std::string& category, const std::vector& ads); std::vector GetUnseenAds(const std::vector& ads); + + bool AdRespectsTotalMaxFrequencyCapping(const AdInfo& ad); + bool AdRespectsPerDayFrequencyCapping(const AdInfo& ad); + bool AdRespectsDailyCapFrequencyCapping(const AdInfo& ad); + std::deque GetCreativeSetForId(const std::string& id); + std::deque GetCampaignForId(const std::string& id); bool IsAdValid(const AdInfo& ad_info); NotificationInfo last_shown_notification_info_; bool ShowAd(const AdInfo& ad_info, const std::string& category); @@ -152,11 +182,6 @@ class AdsImpl : public Ads { void OnTimer(const uint32_t timer_id) override; uint64_t next_easter_egg_timestamp_in_seconds_; - void GenerateAdReportingNotificationShownEvent( - const NotificationInfo& info) override; - void GenerateAdReportingNotificationResultEvent( - const NotificationInfo& info, - const NotificationResultInfoResultType type) override; void GenerateAdReportingConfirmationEvent(const NotificationInfo& info); void GenerateAdReportingLoadEvent(const LoadInfo& info); void GenerateAdReportingBackgroundEvent(); @@ -166,6 +191,11 @@ class AdsImpl : public Ads { void GenerateAdReportingFocusEvent(const FocusInfo& info); void GenerateAdReportingRestartEvent(); void GenerateAdReportingSettingsEvent(); + void GenerateAdReportingNotificationShownEvent( + const NotificationInfo& info); + void GenerateAdReportingNotificationResultEvent( + const NotificationInfo& info, + const NotificationResultInfoResultType type); bool IsNotificationFromSampleCatalog(const NotificationInfo& info) const; @@ -175,6 +205,7 @@ class AdsImpl : public Ads { std::unique_ptr client_; std::unique_ptr bundle_; std::unique_ptr ads_serve_; + std::unique_ptr notifications_; std::unique_ptr user_model_; private: diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ads_tabs_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/ads_tabs_unittest.cc index 902466f2a6b..4029efe59a1 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ads_tabs_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ads_tabs_unittest.cc @@ -140,7 +140,7 @@ class AdsTabsTest : public ::testing::Test { TEST_F(AdsTabsTest, Media_IsPlaying) { // Arrange - ads_->TabUpdated(1, "https://brave.com", true, false); + ads_->OnTabUpdated(1, "https://brave.com", true, false); ads_->OnMediaPlaying(1); // Act @@ -152,7 +152,7 @@ TEST_F(AdsTabsTest, Media_IsPlaying) { TEST_F(AdsTabsTest, Media_NotPlaying) { // Arrange - ads_->TabUpdated(1, "https://brave.com", true, false); + ads_->OnTabUpdated(1, "https://brave.com", true, false); ads_->OnMediaPlaying(1); ads_->OnMediaPlaying(2); @@ -178,7 +178,7 @@ TEST_F(AdsTabsTest, TabUpdated_Incognito) { .Times(0); // Act - ads_->TabUpdated(1, "https://brave.com", true, true); + ads_->OnTabUpdated(1, "https://brave.com", true, true); // Assert auto last_user_activity = ads_->client_->GetLastUserActivity(); @@ -196,7 +196,7 @@ TEST_F(AdsTabsTest, TabUpdated_InactiveIncognito) { .Times(0); // Act - ads_->TabUpdated(1, "https://brave.com", false, true); + ads_->OnTabUpdated(1, "https://brave.com", false, true); // Assert auto last_user_activity = ads_->client_->GetLastUserActivity(); @@ -214,7 +214,7 @@ TEST_F(AdsTabsTest, TabUpdated_Active) { .Times(1); // Act - ads_->TabUpdated(1, "https://brave.com", true, false); + ads_->OnTabUpdated(1, "https://brave.com", true, false); // Assert auto updated_last_user_activity = ads_->client_->GetLastUserActivity(); @@ -232,7 +232,7 @@ TEST_F(AdsTabsTest, TabUpdated_Inactive) { .Times(1); // Act - ads_->TabUpdated(1, "https://brave.com", false, false); + ads_->OnTabUpdated(1, "https://brave.com", false, false); // Assert auto updated_last_user_activity = ads_->client_->GetLastUserActivity(); @@ -247,7 +247,7 @@ TEST_F(AdsTabsTest, TabClosed_WhileMediaIsPlaying) { .Times(1); // Act - ads_->TabClosed(1); + ads_->OnTabClosed(1); // Assert EXPECT_FALSE(ads_->IsMediaPlaying()); diff --git a/vendor/bat-native-ads/src/bat/ads/internal/client.cc b/vendor/bat-native-ads/src/bat/ads/internal/client.cc index 3782a8c338a..2c29390a3a9 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/client.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/client.cc @@ -9,6 +9,8 @@ #include "bat/ads/internal/static_values.h" #include "bat/ads/internal/logging.h" +#include "base/guid.h" + using std::placeholders::_1; using std::placeholders::_2; @@ -16,7 +18,6 @@ namespace ads { Client::Client(AdsImpl* ads, AdsClient* ads_client) : is_initialized_(false), - state_has_loaded_(false), ads_(ads), ads_client_(ads_client), client_state_(new ClientState()) { @@ -24,19 +25,10 @@ Client::Client(AdsImpl* ads, AdsClient* ads_client) : Client::~Client() = default; -void Client::SaveState() { - if (!state_has_loaded_) { - return; - } - - auto json = client_state_->ToJson(); - auto callback = std::bind(&Client::OnStateSaved, this, _1); - ads_client_->Save(_client_name, json, callback); -} +void Client::Initialize(InitializeCallback callback) { + callback_ = callback; -void Client::LoadState() { - auto callback = std::bind(&Client::OnStateLoaded, this, _1, _2); - ads_client_->Load(_client_name, callback); + LoadState(); } void Client::AppendCurrentTimeToAdsShownHistory() { @@ -60,7 +52,7 @@ void Client::UpdateAdUUID() { return; } - client_state_->ad_uuid = ads_client_->GenerateUUID(); + client_state_->ad_uuid = base::GenerateGUID(); SaveState(); } @@ -257,6 +249,16 @@ void Client::RemoveAllHistory() { /////////////////////////////////////////////////////////////////////////////// +void Client::SaveState() { + if (!is_initialized_) { + return; + } + + auto json = client_state_->ToJson(); + auto callback = std::bind(&Client::OnStateSaved, this, _1); + ads_client_->Save(_client_name, json, callback); +} + void Client::OnStateSaved(const Result result) { if (result != SUCCESS) { BLOG(ERROR) << "Failed to save client state"; @@ -267,9 +269,13 @@ void Client::OnStateSaved(const Result result) { BLOG(INFO) << "Successfully saved client state"; } +void Client::LoadState() { + auto callback = std::bind(&Client::OnStateLoaded, this, _1, _2); + ads_client_->Load(_client_name, callback); +} + void Client::OnStateLoaded(const Result result, const std::string& json) { is_initialized_ = true; - state_has_loaded_ = true; if (result != SUCCESS) { BLOG(ERROR) << "Failed to load client state, resetting to default values"; @@ -278,14 +284,14 @@ void Client::OnStateLoaded(const Result result, const std::string& json) { } else { if (!FromJson(json)) { BLOG(ERROR) << "Failed to parse client state: " << json; - + callback_(FAILED); return; } BLOG(INFO) << "Successfully loaded client state"; } - ads_->InitializeStep2(); + callback_(SUCCESS); } bool Client::FromJson(const std::string& json) { diff --git a/vendor/bat-native-ads/src/bat/ads/internal/client.h b/vendor/bat-native-ads/src/bat/ads/internal/client.h index d906d73942a..40f0abe9f1a 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/client.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/client.h @@ -14,7 +14,6 @@ #include #include "bat/ads/ads_client.h" - #include "bat/ads/internal/ads_impl.h" #include "bat/ads/internal/client_state.h" @@ -27,8 +26,7 @@ class Client { Client(AdsImpl* ads, AdsClient* ads_client); ~Client(); - void SaveState(); - void LoadState(); + void Initialize(InitializeCallback callback); void AppendCurrentTimeToAdsShownHistory(); const std::deque GetAdsShownHistory(); @@ -71,9 +69,12 @@ class Client { private: bool is_initialized_; + InitializeCallback callback_; + + void SaveState(); void OnStateSaved(const Result result); - bool state_has_loaded_; + void LoadState(); void OnStateLoaded(const Result result, const std::string& json); bool FromJson(const std::string& json); diff --git a/vendor/bat-native-ads/include/bat/ads/notification_result_type.h b/vendor/bat-native-ads/src/bat/ads/internal/notification_result_type.h similarity index 100% rename from vendor/bat-native-ads/include/bat/ads/notification_result_type.h rename to vendor/bat-native-ads/src/bat/ads/internal/notification_result_type.h diff --git a/vendor/bat-native-ads/src/bat/ads/internal/notifications.cc b/vendor/bat-native-ads/src/bat/ads/internal/notifications.cc new file mode 100644 index 00000000000..9946af9bd74 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/notifications.cc @@ -0,0 +1,371 @@ +/* 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 "bat/ads/internal/notifications.h" +#include "bat/ads/internal/static_values.h" +#include "bat/ads/internal/logging.h" +#include "bat/ads/internal/ads_impl.h" + +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" + +using std::placeholders::_1; +using std::placeholders::_2; + +namespace ads { + +const char kNotificationsStateName[] = "notifications.json"; + +const char kNotificationsListKey[] = "notifications"; + +const char kNotificationIdKey[] = "id"; +const char kNotificationCreativeSetIdKey[] = "creative_set_id"; +const char kNotificationCategoryKey[] = "category"; +const char kNotificationAdvertiserKey[] = "advertiser"; +const char kNotificationTextKey[] = "text"; +const char kNotificationUrlKey[] = "url"; +const char kNotificationUuidKey[] = "uuid"; + +Notifications::Notifications(AdsImpl* ads, AdsClient* ads_client) : + is_initialized_(false), + notifications_({}), + ads_(ads), + ads_client_(ads_client) { + (void)ads_; + + BLOG(INFO) << "Initializing notifications"; +} + +Notifications::~Notifications() { + BLOG(INFO) << "Deinitializing notifications"; +} + +void Notifications::Initialize(InitializeCallback callback) { + callback_ = callback; + + LoadState(); +} + +bool Notifications::Get(const std::string& id, NotificationInfo* info) { + DCHECK(is_initialized_); + + auto notification = notifications_.find(id); + if (notification == notifications_.end()) { + return false; + } + + *info = notification->second; + + return true; +} + +void Notifications::Add(const NotificationInfo& info) { + DCHECK(is_initialized_); + + notifications_.insert({info.id, info}); + + SaveState(); +} + +bool Notifications::Remove(const std::string& id) { + DCHECK(is_initialized_); + + if (!Exists(id)) { + return false; + } + + ads_client_->CloseNotification(id); + notifications_.erase(id); + + SaveState(); + + return true; +} + +void Notifications::RemoveAll() { + DCHECK(is_initialized_); + + for (const auto& notification : notifications_) { + auto id = notification.first; + Remove(id); + } + + SaveState(); +} + +bool Notifications::Exists(const std::string& id) { + DCHECK(is_initialized_); + + if (notifications_.find(id) == notifications_.end()) { + return false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +std::map Notifications::GetNotificationsFromList( + base::ListValue* list) const { + DCHECK(list); + + std::map notifications; + + for (auto& item : *list) { + base::DictionaryValue* dictionary; + if (!item.GetAsDictionary(&dictionary)) { + continue; + } + + NotificationInfo notification_info; + if (!GetNotificationFromDictionary(dictionary, ¬ification_info)) { + continue; + } + + notifications.insert({notification_info.id, notification_info}); + } + + return notifications; +} + +bool Notifications::GetNotificationFromDictionary( + base::DictionaryValue* dictionary, + NotificationInfo* info) const { + NotificationInfo notification_info; + + if (!GetIdFromDictionary(dictionary, ¬ification_info.id)) { + return false; + } + + if (!GetCreativeSetIdFromDictionary(dictionary, + ¬ification_info.creative_set_id)) { + return false; + } + + if (!GetCategoryFromDictionary(dictionary, ¬ification_info.category)) { + return false; + } + + if (!GetAdvertiserFromDictionary(dictionary, ¬ification_info.advertiser)) { + return false; + } + + if (!GetTextFromDictionary(dictionary, ¬ification_info.text)) { + return false; + } + + if (!GetUrlFromDictionary(dictionary, ¬ification_info.url)) { + return false; + } + + if (!GetUuidFromDictionary(dictionary, ¬ification_info.uuid)) { + return false; + } + + *info = NotificationInfo(notification_info); + + return true; +} + +bool Notifications::GetIdFromDictionary( + base::DictionaryValue* dictionary, + std::string* value) const { + return GetStringFromDictionary(kNotificationIdKey, dictionary, value); +} + +bool Notifications::GetCreativeSetIdFromDictionary( + base::DictionaryValue* dictionary, + std::string* value) const { + return GetStringFromDictionary(kNotificationCreativeSetIdKey, + dictionary, value); +} + +bool Notifications::GetCategoryFromDictionary( + base::DictionaryValue* dictionary, + std::string* value) const { + return GetStringFromDictionary(kNotificationCategoryKey, dictionary, value); +} + +bool Notifications::GetAdvertiserFromDictionary( + base::DictionaryValue* dictionary, + std::string* value) const { + return GetStringFromDictionary(kNotificationAdvertiserKey, dictionary, value); +} + +bool Notifications::GetTextFromDictionary( + base::DictionaryValue* dictionary, + std::string* value) const { + return GetStringFromDictionary(kNotificationTextKey, dictionary, value); +} + +bool Notifications::GetUrlFromDictionary( + base::DictionaryValue* dictionary, + std::string* value) const { + return GetStringFromDictionary(kNotificationUrlKey, dictionary, value); +} + +bool Notifications::GetUuidFromDictionary( + base::DictionaryValue* dictionary, + std::string* value) const { + return GetStringFromDictionary(kNotificationUuidKey, dictionary, value); +} + +bool Notifications::GetStringFromDictionary( + const std::string& key, + base::DictionaryValue* dictionary, + std::string* string) const { + DCHECK(dictionary); + DCHECK(string); + + auto* value = dictionary->FindKey(key); + if (!value || !value->is_string()) { + return false; + } + + auto string_value = value->GetString(); + + *string = string_value; + + return true; +} + +void Notifications::SaveState() { + if (!is_initialized_) { + return; + } + + BLOG(INFO) << "Saving notifications state"; + + std::string json = ToJson(); + auto callback = std::bind(&Notifications::OnStateSaved, this, _1); + ads_client_->Save(kNotificationsStateName, json, callback); +} + +void Notifications::OnStateSaved(const Result result) { + if (result != SUCCESS) { + BLOG(ERROR) << "Failed to save notifications state"; + return; + } + + BLOG(INFO) << "Successfully saved notifications state"; +} + +void Notifications::LoadState() { + BLOG(INFO) << "Loading notifications state"; + + auto callback = std::bind(&Notifications::OnStateLoaded, this, _1, _2); + ads_client_->Load(kNotificationsStateName, callback); +} + +void Notifications::OnStateLoaded( + const Result result, + const std::string& json) { + is_initialized_ = true; + + if (result != SUCCESS) { + BLOG(ERROR) + << "Failed to load notifications state, resetting to default values"; + + notifications_.clear(); + } else { + if (!FromJson(json)) { + BLOG(ERROR) << "Failed to parse notifications state: " << json; + + callback_(FAILED); + return; + } + + BLOG(INFO) << "Successfully loaded notifications state"; + } + + callback_(SUCCESS); +} + +bool Notifications::FromJson(const std::string& json) { + base::Optional value = base::JSONReader::Read(json); + if (!value || !value->is_dict()) { + return false; + } + + base::DictionaryValue* dictionary = nullptr; + if (!value->GetAsDictionary(&dictionary)) { + return false; + } + + if (!GetNotificationsFromJson(dictionary)) { + BLOG(WARNING) << "Failed to get notifications from JSON: " << json; + return false; + } + + SaveState(); + + return true; +} + +bool Notifications::GetNotificationsFromJson( + base::DictionaryValue* dictionary) { + DCHECK(dictionary); + + auto* value = dictionary->FindKey(kNotificationsListKey); + if (!value || !value->is_list()) { + return false; + } + + base::ListValue* list = nullptr; + if (!value->GetAsList(&list)) { + return false; + } + + notifications_ = GetNotificationsFromList(list); + + return true; +} + +std::string Notifications::ToJson() { + base::Value dictionary(base::Value::Type::DICTIONARY); + + auto notifications = GetAsList(); + dictionary.SetKey(kNotificationsListKey, + base::Value(std::move(notifications))); + + // Write to JSON + std::string json; + base::JSONWriter::Write(dictionary, &json); + + return json; +} + +base::Value Notifications::GetAsList() { + base::Value list(base::Value::Type::LIST); + + for (const auto& notification : notifications_) { + NotificationInfo notification_info = NotificationInfo(notification.second); + + base::Value dictionary(base::Value::Type::DICTIONARY); + + dictionary.SetKey(kNotificationIdKey, + base::Value(notification_info.id)); + dictionary.SetKey(kNotificationCreativeSetIdKey, + base::Value(notification_info.creative_set_id)); + dictionary.SetKey(kNotificationCategoryKey, + base::Value(notification_info.category)); + dictionary.SetKey(kNotificationAdvertiserKey, + base::Value(notification_info.advertiser)); + dictionary.SetKey(kNotificationTextKey, + base::Value(notification_info.text)); + dictionary.SetKey(kNotificationUrlKey, + base::Value(notification_info.url)); + dictionary.SetKey(kNotificationUuidKey, + base::Value(notification_info.uuid)); + + list.GetList().push_back(std::move(dictionary)); + } + + return list; +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/notifications.h b/vendor/bat-native-ads/src/bat/ads/internal/notifications.h new file mode 100644 index 00000000000..f8670a225cd --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/notifications.h @@ -0,0 +1,97 @@ +/* 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 BAT_ADS_INTERNAL_NOTIFICATIONS_H_ +#define BAT_ADS_INTERNAL_NOTIFICATIONS_H_ + +#include +#include + +#include "bat/ads/ads_client.h" +#include "bat/ads/internal/ads_impl.h" +#include "bat/ads/notification_info.h" + +#include "base/values.h" + +namespace ads { + +class AdsImpl; + +class Notifications { + public: + Notifications(AdsImpl* ads, AdsClient* ads_client); + ~Notifications(); + + void Initialize(InitializeCallback callback); + + bool Get(const std::string& id, NotificationInfo* info); + + void Add(const NotificationInfo& info); + + bool Remove(const std::string& id); + void RemoveAll(); + + bool Exists(const std::string& id); + + private: + bool is_initialized_; + + InitializeCallback callback_; + + std::map notifications_; + + std::map GetNotificationsFromList( + base::ListValue* list) const; + + bool GetNotificationFromDictionary( + base::DictionaryValue* dictionary, + NotificationInfo* info) const; + + bool GetIdFromDictionary( + base::DictionaryValue* dictionary, + std::string* value) const; + bool GetCreativeSetIdFromDictionary( + base::DictionaryValue* dictionary, + std::string* value) const; + bool GetCategoryFromDictionary( + base::DictionaryValue* dictionary, + std::string* value) const; + bool GetAdvertiserFromDictionary( + base::DictionaryValue* dictionary, + std::string* value) const; + bool GetTextFromDictionary( + base::DictionaryValue* dictionary, + std::string* value) const; + bool GetUrlFromDictionary( + base::DictionaryValue* dictionary, + std::string* value) const; + bool GetUuidFromDictionary( + base::DictionaryValue* dictionary, + std::string* value) const; + + bool GetStringFromDictionary( + const std::string& key, + base::DictionaryValue* dictionary, + std::string* string) const; + + void SaveState(); + void OnStateSaved(const Result result); + + void LoadState(); + void OnStateLoaded(const Result result, const std::string& json); + + bool FromJson(const std::string& json); + bool GetNotificationsFromJson(base::DictionaryValue* dictionary); + + std::string ToJson(); + base::Value GetAsList(); + + AdsImpl* ads_; // NOT OWNED + AdsClient* ads_client_; // NOT OWNED +}; + +} // namespace ads + +#endif // BAT_ADS_INTERNAL_NOTIFICATIONS_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/notification_info.cc b/vendor/bat-native-ads/src/bat/ads/notification_info.cc index c2b2559e94b..d4dddb66718 100644 --- a/vendor/bat-native-ads/src/bat/ads/notification_info.cc +++ b/vendor/bat-native-ads/src/bat/ads/notification_info.cc @@ -13,6 +13,7 @@ namespace ads { NotificationInfo::NotificationInfo() : + id(""), creative_set_id(""), category(""), advertiser(""), @@ -22,6 +23,7 @@ NotificationInfo::NotificationInfo() : type(ConfirmationType::UNKNOWN) {} NotificationInfo::NotificationInfo(const NotificationInfo& info) : + id(info.id), creative_set_id(info.creative_set_id), category(info.category), advertiser(info.advertiser), @@ -52,6 +54,10 @@ Result NotificationInfo::FromJson( return FAILED; } + if (document.HasMember("id")) { + id = document["id"].GetString(); + } + if (document.HasMember("creative_set_id")) { creative_set_id = document["creative_set_id"].GetString(); } @@ -87,6 +93,9 @@ Result NotificationInfo::FromJson( void SaveToJson(JsonWriter* writer, const NotificationInfo& info) { writer->StartObject(); + writer->String("id"); + writer->String(info.id.c_str()); + writer->String("creative_set_id"); writer->String(info.creative_set_id.c_str()); diff --git a/vendor/bat-native-confirmations/include/bat/confirmations/notification_info.h b/vendor/bat-native-confirmations/include/bat/confirmations/notification_info.h index a167964dbad..c95250651b2 100644 --- a/vendor/bat-native-confirmations/include/bat/confirmations/notification_info.h +++ b/vendor/bat-native-confirmations/include/bat/confirmations/notification_info.h @@ -18,6 +18,7 @@ struct CONFIRMATIONS_EXPORT NotificationInfo { explicit NotificationInfo(const NotificationInfo& info); ~NotificationInfo(); + std::string id; std::string creative_set_id; std::string category; std::string advertiser; diff --git a/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmations_impl.cc b/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmations_impl.cc index 8541fd4a231..d6210f8a322 100644 --- a/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmations_impl.cc +++ b/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmations_impl.cc @@ -999,14 +999,14 @@ void ConfirmationsImpl::AppendTransactionToHistory( } void ConfirmationsImpl::ConfirmAd(std::unique_ptr info) { - BLOG(INFO) << "ConfirmAd:"; - BLOG(INFO) << " creative_set_id: " << info->creative_set_id; - BLOG(INFO) << " category: " << info->category; - BLOG(INFO) << " url: " << info->url; - BLOG(INFO) << " text: " << info->text; - BLOG(INFO) << " advertiser: " << info->advertiser; - BLOG(INFO) << " uuid: " << info->uuid; - BLOG(INFO) << " type: " << std::string(info->type); + BLOG(INFO) << "Confirm ad:" + << std::endl << " id: " << info->id + << std::endl << " advertiser: " << info->advertiser + << std::endl << " category: " << info->category + << std::endl << " notificationText: " << info->text + << std::endl << " notificationUrl: " << info->url + << std::endl << " uuid: " << info->uuid + << std::endl << " type: " << std::string(info->type); redeem_token_->Redeem(info->uuid, info->type); } diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.cc index 80366e24c05..79f5b8b27aa 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.cc +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.cc @@ -1477,6 +1477,7 @@ void LedgerImpl::ConfirmAd(const std::string& info) { return; auto notification_info = std::make_unique(); + notification_info->id = notification_info_ads.id; notification_info->creative_set_id = notification_info_ads.creative_set_id; notification_info->category = notification_info_ads.category; notification_info->advertiser = notification_info_ads.advertiser; diff --git a/vendor/brave-ios/Ads/BATBraveAds.mm b/vendor/brave-ios/Ads/BATBraveAds.mm index 717aa961654..66bb1d93f67 100644 --- a/vendor/brave-ios/Ads/BATBraveAds.mm +++ b/vendor/brave-ios/Ads/BATBraveAds.mm @@ -218,12 +218,12 @@ - (void)reportMediaStoppedWithTabId:(NSInteger)tabId - (void)reportTabUpdated:(NSInteger)tabId url:(NSURL *)url isSelected:(BOOL)isSelected isPrivate:(BOOL)isPrivate { const auto urlString = std::string(url.absoluteString.UTF8String); - ads->TabUpdated((int32_t)tabId, urlString, isSelected, isPrivate); + ads->OnTabUpdated((int32_t)tabId, urlString, isSelected, isPrivate); } - (void)reportTabClosedWithTabId:(NSInteger)tabId { - ads->TabClosed((int32_t)tabId); + ads->OnTabClosed((int32_t)tabId); } #pragma mark - Ads Bridge @@ -233,8 +233,6 @@ - (void)showNotification:(std::unique_ptr)info if (info.get() != nullptr) { const auto notification = [[BATAdsNotification alloc] initWithNotificationInfo:*info.get()]; [self.delegate braveAds:self showNotification:notification]; - - ads->GenerateAdReportingNotificationShownEvent(*info.get()); } } @@ -454,11 +452,4 @@ - (void)eventLog:(const std::string &)json return std::make_unique(file, line, log_level); } -#pragma mark - Misc - -- (const std::string)generateUUID -{ - return [self.commonOps generateUUID]; -} - @end diff --git a/vendor/brave-ios/Ads/Generated/NativeAdsClient.h b/vendor/brave-ios/Ads/Generated/NativeAdsClient.h index 1be3c96d955..69a33fdd025 100644 --- a/vendor/brave-ios/Ads/Generated/NativeAdsClient.h +++ b/vendor/brave-ios/Ads/Generated/NativeAdsClient.h @@ -19,7 +19,6 @@ class NativeAdsClient : public ads::AdsClient { void ConfirmAd(std::unique_ptr info) override; void EventLog(const std::string & json) override; - const std::string GenerateUUID() const override; void GetAds(const std::string & category, ads::OnGetAdsCallback callback) override; const std::string GetAdsLocale() const override; uint64_t GetAdsPerDay() const override; @@ -43,5 +42,6 @@ class NativeAdsClient : public ads::AdsClient { void SetIdleThreshold(const int threshold) override; uint32_t SetTimer(const uint64_t time_offset) override; void ShowNotification(std::unique_ptr info) override; + void CloseNotification(const std::string& id) override; void URLRequest(const std::string & url, const std::vector & headers, const std::string & content, const std::string & content_type, const ads::URLRequestMethod method, ads::URLRequestCallback callback) override; }; diff --git a/vendor/brave-ios/Ads/Generated/NativeAdsClient.mm b/vendor/brave-ios/Ads/Generated/NativeAdsClient.mm index d1324ca20d0..4d1eafb9f97 100644 --- a/vendor/brave-ios/Ads/Generated/NativeAdsClient.mm +++ b/vendor/brave-ios/Ads/Generated/NativeAdsClient.mm @@ -19,9 +19,6 @@ void NativeAdsClient::EventLog(const std::string & json) { [bridge_ eventLog:json]; } -const std::string NativeAdsClient::GenerateUUID() const { - return [bridge_ generateUUID]; -} void NativeAdsClient::GetAds(const std::string & category, ads::OnGetAdsCallback callback) { [bridge_ getAds:category callback:callback]; } diff --git a/vendor/brave-ios/Ads/Generated/NativeAdsClientBridge.h b/vendor/brave-ios/Ads/Generated/NativeAdsClientBridge.h index b94cda6091a..0103701fcd6 100644 --- a/vendor/brave-ios/Ads/Generated/NativeAdsClientBridge.h +++ b/vendor/brave-ios/Ads/Generated/NativeAdsClientBridge.h @@ -12,7 +12,6 @@ - (void)confirmAd:(std::unique_ptr)info; - (void)eventLog:(const std::string &)json; -- (const std::string)generateUUID; - (void)getAds:(const std::string &)category callback:(ads::OnGetAdsCallback)callback; - (const std::string)getAdsLocale; - (uint64_t)getAdsPerDay; @@ -36,6 +35,7 @@ - (void)setIdleThreshold:(const int)threshold; - (uint32_t)setTimer:(const uint64_t)time_offset; - (void)showNotification:(std::unique_ptr)info; +- (void)closeNotification:(const std::string &)id; - (void)URLRequest:(const std::string &)url headers:(const std::vector &)headers content:(const std::string &)content contentType:(const std::string &)content_type method:(const ads::URLRequestMethod)method callback:(ads::URLRequestCallback)callback; @end