blob: c7705de8de1601ba92cf6138561cd89fb90258a9 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_PROMOS_MANAGER_PROMOS_MANAGER_IMPL_H_
#define IOS_CHROME_BROWSER_PROMOS_MANAGER_PROMOS_MANAGER_IMPL_H_
#import "ios/chrome/browser/promos_manager/promos_manager.h"
#import <Foundation/Foundation.h>
#import <map>
#import <optional>
#import <set>
#import <vector>
#import "base/containers/small_map.h"
#import "base/time/clock.h"
#import "base/values.h"
#import "components/prefs/pref_service.h"
#import "ios/chrome/browser/promos_manager/constants.h"
#import "ios/chrome/browser/promos_manager/impression_limit.h"
#import "ios/chrome/browser/promos_manager/promo_config.h"
namespace feature_engagement {
class Tracker;
}
class PromosManagerEventExporter;
// Centralized promos manager for coordinating and scheduling the display of
// app-wide promos. Feature teams should not use this directly, use
// promo_manager.h instead.
class PromosManagerImpl : public PromosManager {
public:
// Context for a promo registration, internally used.
struct PromoContext {
// The promo has had pending status.
bool was_pending;
};
PromosManagerImpl(PrefService* local_state,
base::Clock* clock,
feature_engagement::Tracker* tracker,
PromosManagerEventExporter* event_exporter);
~PromosManagerImpl() override;
// Loads and sorts impression history from prefs.
void RefreshImpressionHistoryFromPrefs();
// `promo`-specific impression limits, if defined. May return an empty
// NSArray, indicating no promo-specific impression limits were defined for
// `promo`.
NSArray<ImpressionLimit*>* PromoImpressionLimits(
promos_manager::Promo promo) const;
// Sorts the active promos in the order that they will be displayed.
std::vector<promos_manager::Promo> SortPromos(
const std::map<promos_manager::Promo, PromoContext>&
promos_to_sort_with_context) const;
// Impression limits that count against all promos.
NSArray<ImpressionLimit*>* GlobalImpressionLimits() const;
// Impression limits that count against any given promo.
NSArray<ImpressionLimit*>* GlobalPerPromoImpressionLimits() const;
// Loops over the stored impression history (base::Value::List) and returns
// corresponding a std::vector<promos_manager::Impression>.
std::vector<promos_manager::Impression> ImpressionHistory(
const base::Value::List& stored_impression_history);
// Loops over the stored active promos list (base::Value::List) and returns
// a corresponding std::set<promos_manager::Promo>.
std::set<promos_manager::Promo> ActivePromos(
const base::Value::List& stored_active_promos) const;
// Initializes the `single_display_pending_promos_`, constructs it from Pref.
void InitializePendingPromos();
void OnFeatureEngagementTrackerInitialized(bool success);
// Returns true if any impression limit from `impression_limits` is triggered,
// and false otherwise.
//
// At each limit, evaluates the following:
//
// (1) Is the current limit valid for evaluation? This is determined by
// whether or not `window_days` is < the current limit's window.
//
// (2) If the limit is valid for evaluation, compare `impression_count` with
// the current limit's impression count. If `impression_count` >= the current
// limit's impression count, the limit has been triggered.
// (3) If the limit is triggered, exits early and returns true. Otherwise,
// keep going.
bool AnyImpressionLimitTriggered(
int impression_count,
int window_days,
NSArray<ImpressionLimit*>* impression_limits) const;
// Algorithm loops over pre-sorted impressions history list. The algorithm
// assumes `valid_impressions` is sorted by impression day (most recent ->
// least recent).
//
// At each impression, the algorithm asks if either a time-based or
// time-agnostic impression limit has been met. If so, the algorithm exits
// early and returns false.
//
// If the algorithm reaches its end, no impression limits were hit for
// `promo`. If so, the algorithm returns true, as it's safe to display
// `promo`.
bool CanShowPromo(
promos_manager::Promo promo,
const std::vector<promos_manager::Impression>& sorted_impressions) const;
// Checks whether a promo can currently be shown using the feature engagement
// system to check any impression limits.
bool CanShowPromoUsingFeatureEngagementTracker(
promos_manager::Promo promo) const;
// Returns the corresponding base::Feature for the given Promo.
const base::Feature* FeatureForPromo(promos_manager::Promo promo) const;
// Returns a list of impression counts (std::vector<int>) from a promo
// impression counts map.
std::vector<int> ImpressionCounts(
std::map<promos_manager::Promo, int>& promo_impression_counts) const;
// Returns the total number of impressions (int) from a promo impression
// counts map.
int TotalImpressionCount(
std::map<promos_manager::Promo, int>& promo_impression_counts) const;
// PromosManager implementation.
void Init() override;
void InitializePromoConfigs(PromoConfigsSet promo_configs) override;
void RecordImpression(promos_manager::Promo promo) override;
std::optional<promos_manager::Promo> NextPromoForDisplay() override;
void RegisterPromoForContinuousDisplay(promos_manager::Promo promo) override;
void RegisterPromoForSingleDisplay(promos_manager::Promo promo) override;
void RegisterPromoForSingleDisplay(
promos_manager::Promo promo,
base::TimeDelta becomes_active_after_period) override;
void DeregisterPromo(promos_manager::Promo promo) override;
// Weak pointer to the local state prefs store.
const raw_ptr<PrefService> local_state_;
// The time provider.
const raw_ptr<base::Clock> clock_;
// The feature engagement tracker.
raw_ptr<feature_engagement::Tracker> tracker_;
// The set of currently active, continuous-display promos.
std::set<promos_manager::Promo> active_promos_;
// The set of currently active, single-display promos.
std::set<promos_manager::Promo> single_display_active_promos_;
// The map from registered single-display pending promos to the time that they
// can become active.
std::map<promos_manager::Promo, base::Time> single_display_pending_promos_;
// The impression history sorted by `day` (most recent -> least recent).
std::vector<promos_manager::Impression> impression_history_;
// Promo-specific configuration.
PromoConfigsSet promo_configs_;
// The class to handle migrating events to the Feature Engagement Tracker.
PromosManagerEventExporter* event_exporter_;
base::WeakPtrFactory<PromosManagerImpl> weak_ptr_factory_{this};
};
#endif // IOS_CHROME_BROWSER_PROMOS_MANAGER_PROMOS_MANAGER_IMPL_H_