blob: 2aabe457bb3c5780469abfc826cef49a3a2068e6 [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 <set>
#import <vector>
#import "base/containers/small_map.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 "third_party/abseil-cpp/absl/types/optional.h"
// 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:
explicit PromosManagerImpl(PrefService* local_state);
~PromosManagerImpl() override;
// `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;
// Returns a std::vector<promos_manager::Promo> that only includes promos in
// `active_promos`, sorted by day (least recent -> most recent).
//
// Assumes that `sorted_impressions` is sorted by day (most recent -> least
// recent).
//
// When `active_promos` or `sorted_impressions` is empty, returns an empty
// array.
//
// Promos that have never been shown before are considered less recently shown
// than promos that have been shown.
//
// Promos shown on the same day will be sorted by relative position. More
// concretely, even if two promos are shown on the same day, the promos with
// the lower index in the impressions history list will be considered more
// recently seen, as `sorted_impressions` is sorted by day (most recent ->
// least recent).
std::vector<promos_manager::Promo> LeastRecentlyShown(
const std::set<promos_manager::Promo>& active_promos,
const std::vector<promos_manager::Impression>& sorted_impressions) 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);
// 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;
// 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 greatest impression count (int) from a promo impression counts
// map.
int MaxImpressionCount(
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 InitializePromoImpressionLimits(
base::small_map<
std::map<promos_manager::Promo, NSArray<ImpressionLimit*>*>>
promo_impression_limits) override;
void RecordImpression(promos_manager::Promo promo) override;
absl::optional<promos_manager::Promo> NextPromoForDisplay() const override;
void RegisterPromoForContinuousDisplay(promos_manager::Promo promo) override;
void RegisterPromoForSingleDisplay(promos_manager::Promo promo) override;
void DeregisterPromo(promos_manager::Promo promo) override;
// Weak pointer to the local state prefs store.
const raw_ptr<PrefService> local_state_;
// 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 impression history sorted by `day` (most recent -> least recent).
std::vector<promos_manager::Impression> impression_history_;
// Promo-specific impression limits (promos_manager::Promo : [Impression
// Limits]).
base::small_map<std::map<promos_manager::Promo, NSArray<ImpressionLimit*>*>>
promo_impression_limits_;
};
#endif // IOS_CHROME_BROWSER_PROMOS_MANAGER_PROMOS_MANAGER_IMPL_H_