chromium/ios/chrome/browser/default_browser/model/utils.h

// Copyright 2020 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_DEFAULT_BROWSER_MODEL_UTILS_H_
#define IOS_CHROME_BROWSER_DEFAULT_BROWSER_MODEL_UTILS_H_

#import <UIKit/UIKit.h>

#import "base/feature_list.h"
#import "ios/chrome/browser/default_browser/model/promo_statistics.h"

namespace feature_engagement {
class Tracker;
}
namespace base {
class Time;
class TimeDelta;
}

// Enum for the different types of default browser modal promo. These are stored
// as values, if adding a new one, make sure to add it at the end.
typedef NS_ENUM(NSUInteger, DefaultPromoType) {
  DefaultPromoTypeGeneral = 0,
  DefaultPromoTypeStaySafe = 1,
  DefaultPromoTypeMadeForIOS = 2,
  DefaultPromoTypeAllTabs = 3,
};

// Enum actions for default browser promo UMA metrics. Entries should not be
// renumbered and numeric values should never be reused.
enum class IOSDefaultBrowserPromoAction {
  kActionButton = 0,
  kCancel = 1,
  kRemindMeLater = 2,
  kDismiss = 3,
  kMaxValue = kDismiss,
};

// Enum for the default browser promo UMA histograms. These values are persisted
// to logs. Entries should not be renumbered and numeric values should never be
// reused.
enum class DefaultPromoTypeForUMA {
  kGeneral = 0,
  kMadeForIOS = 1,
  kStaySafe = 2,
  kAllTabs = 3,
  kMaxValue = kAllTabs,
};

// Enum actions for the IOS.DefaultBrowserVideoPromo.(Fullscreen || Halfscreen)*
// UMA metrics.
enum class IOSDefaultBrowserVideoPromoAction {
  kPrimaryActionTapped = 0,
  kSecondaryActionTapped = 1,
  kSwipeDown = 2,
  kTertiaryActionTapped = 3,
  kMaxValue = kTertiaryActionTapped,
};

// Visible for testing

// Key in storage containing an NSDate corresponding to the last time
// an HTTP(S) link was sent and opened by the app.
extern NSString* const kLastHTTPURLOpenTime;

// Key in storage containing an NSDate indicating the last time a user
// interacted with a non-modal promo.
extern NSString* const kLastTimeUserInteractedWithNonModalPromo;

// Key in storage containing an NSDate indicating the last time a user
// interacted with ANY full screen promo. The string value is kept from when the
// promos first launched to avoid changing the behavior for users that have
// already seen the promo.
extern NSString* const kLastTimeUserInteractedWithFullscreenPromo;

// Key in storage containing all the recent timestamps of browser cold starts up
// to allowed maximum number of past events.
extern NSString* const kAllTimestampsAppLaunchColdStart;

// Key in storage containing all the recent timestamps of browser warm starts up
// to allowed maximum number of past events.
extern NSString* const kAllTimestampsAppLaunchWarmStart;

// Key in storage containing all the recent timestamps of browser indirect
// starts up to allowed maximum number of past events.
extern NSString* const kAllTimestampsAppLaunchIndirectStart;

// Key in storage containing an array of dates. Each date correspond to
// a stay safe event of interest for Default Browser Promo modals.
extern NSString* const kLastSignificantUserEventStaySafe;

// Key in storage containing an array of dates. Each date correspond to
// a omnibox copy-paste event up to allowed maximum number of past events.
extern NSString* const kOmniboxUseCount;

// Key in storage containing an array of dates. Each date correspond to
// a bookmark or bookmark manager use event up to allowed maximum number of past
// events.
extern NSString* const kBookmarkUseCount;

// Key in storage containing an array of dates. Each date correspond to
// a autofill suggestion use event up to allowed maximum number of past
// events.
extern NSString* const kAutofillUseCount;

// Key in storage containing an array of dates where each date correspond to
// a pinned tab or remote tab use event.
extern NSString* const kSpecialTabsUseCount;

// Param names used for the default browser video promo.
extern const char kVideoFullscreenPromo[];
extern const char kVideoHalfscreenPromo[];
extern const char kDefaultBrowserVideoPromoVariant[];

// Key in storage containing a bool indicating if the user has
// previously interacted with a regular fullscreen promo.
extern NSString* const kUserHasInteractedWithFullscreenPromo;

// Key in storage containing a bool indicating if the user has
// previously interacted with a tailored fullscreen promo.
extern NSString* const kUserHasInteractedWithTailoredFullscreenPromo;

// Key in storage containing a bool indicating if the user has
// previously interacted with first run promo.
extern NSString* const kUserHasInteractedWithFirstRunPromo;

// Key in storage containing an int indicating the number of times a fullscreen
// promo has been displayed.
extern NSString* const kDisplayedFullscreenPromoCount;

// Key in storage containing an int indicating the number of times a generic
// promo has been displayed.
extern NSString* const kGenericPromoInteractionCount;

// Key in storage containing an int indicating the number of times a tailored
// promo has been displayed.
extern NSString* const kTailoredPromoInteractionCount;

// Key in storage containing the timestamp of when trigger criteria experiment
// started.
extern NSString* const kTimestampTriggerCriteriaExperimentStarted;

// Specifies how long blue dot occurrence should last.
extern base::TimeDelta const kBlueDotPromoDuration;

// Specifies how often blue dot should reoccur.
extern base::TimeDelta const kBlueDotPromoReoccurrancePeriod;

// Loads from NSUserDefaults the time of the non-expired events for the
// given promo type.
std::vector<base::Time> LoadTimestampsForPromoType(DefaultPromoType type);

// Stores the time of the last recorded events for `type`.
void StoreTimestampsForPromoType(DefaultPromoType type,
                                 std::vector<base::Time> times);

// Helper function to set `data` for `key` into the storage object.
void SetObjectIntoStorageForKey(NSString* key, NSObject* data);

// Logs the timestamp of opening an HTTP(S) link sent and opened by the app.
void LogOpenHTTPURLFromExternalURL();

// Logs the timestamp of user activity that is deemed to be an indication of
// a user that would likely benefit from having Chrome set as their default
// browser. Before logging the current activity, this method will also clear all
// past expired logs for `type` that have happened too far in the past.
void LogLikelyInterestedDefaultBrowserUserActivity(DefaultPromoType type);

// Logs to the FET that a default browser promo has been shown.
void LogToFETDefaultBrowserPromoShown(feature_engagement::Tracker* tracker);

// Returns whether blue dot display timestamp has already been set.
bool HasDefaultBrowserBlueDotDisplayTimestamp();

// Resets  blue dot display timestamp to its default value when needed.
void ResetDefaultBrowserBlueDotDisplayTimestampIfNeeded();

// Set the current timestamp as blue dot first display timestamp if this was the
// first instance.
void RecordDefaultBrowserBlueDotFirstDisplay();

// Returns true if the default browser blue dot should be shown.
bool ShouldTriggerDefaultBrowserHighlightFeature(
    feature_engagement::Tracker* tracker);

// Returns true if the non-modal default browser promo cooldown refactor is
// enabled.
bool IsNonModalDefaultBrowserPromoCooldownRefactorEnabled();

// Returns true if client is in Default Browser promo trigger criteria
// experiment.
bool IsDefaultBrowserTriggerCriteraExperimentEnabled();

// Sets trigger criteria experiment start timestamp to now.
void SetTriggerCriteriaExperimentStartTimestamp();

// Returns true if trigger criteria experiment has been started.
bool HasTriggerCriteriaExperimentStarted();

// Returns true if trigger criteria experiment has been started for at least 21
// days.
bool HasTriggerCriteriaExperimentStarted21days();

// Returns true if the default browser promo generic tailored experiment is
// enabled.
bool IsDefaultBrowserPromoGenericTailoredTrainEnabled();

// Returns true if the only-generic arm of the default browser promo generic
// tailored experiment is enabled.
bool IsDefaultBrowserPromoOnlyGenericArmTrain();

// Returns true if the user has interacted with the Fullscreen Promo previously.
// Returns false otherwise.
bool HasUserInteractedWithFullscreenPromoBefore();

// Returns true if the user has interacted with a tailored Fullscreen Promo
// previously. Returns false otherwise.
bool HasUserInteractedWithTailoredFullscreenPromoBefore();

// Returns the number of times the user has seen and interacted with the
// non-modal promo before.
NSInteger UserInteractionWithNonModalPromoCount();

// Returns the number of times a fullscreen default browser promo has been
// displayed.
NSInteger DisplayedFullscreenPromoCount();

// Logs that one of the fullscreen default browser promos was displayed.
void LogFullscreenDefaultBrowserPromoDisplayed();

// Logs that the user has interacted with the Fullscreen Promo.
void LogUserInteractionWithFullscreenPromo();

// Logs that the user has interacted with a Tailored Fullscreen Promo.
void LogUserInteractionWithTailoredFullscreenPromo();

// Logs that the user has interacted with a non-modal promo. The expected
// parameters are the current counts, because they will be incremented by 1 and
// then saved to NSUserDefaults. If kNonModalDefaultBrowserPromoCooldownRefactor
// is disabled, kDisplayedFullscreenPromoCount will also be incremented by 1.
void LogUserInteractionWithNonModalPromo(
    NSInteger currentNonModalPromoInteractionsCount,
    NSInteger currentFullscreenPromoInteractionsCount);

// Logs that the user has interacted with the first run promo.
void LogUserInteractionWithFirstRunPromo();

// Logs in NSUserDefaults that user copy-pasted in the omnibox.
void LogCopyPasteInOmniboxForCriteriaExperiment();

// Logs in NSUserDefaults that user used bookmarks or bookmark manager.
void LogBookmarkUseForCriteriaExperiment();

// Logs in NSUserDefaults that user used autofill suggestions
void LogAutofillUseForCriteriaExperiment();

// Logs that the user has used remote tabs.
void LogRemoteTabsUseForCriteriaExperiment();

// Returns true if the last URL open is within the specified number of `days`
// which would indicate Chrome is likely still the default browser. Returns
// false otherwise.
bool IsChromeLikelyDefaultBrowserXDays(int days);

// Returns true if the last URL open is within the time threshold that would
// indicate Chrome is likely still the default browser. Returns false otherwise.
bool IsChromeLikelyDefaultBrowser();

// Do not use. Only for backward compatibility
// Returns true if the last URL open is within 7 days. Returns false otherwise.
bool IsChromeLikelyDefaultBrowser7Days();

// Returns true if Chrome was likely the default browser in the last
// `likelyDefaultInterval` days but not in the last `likelyNotDefaultInterval`
// days.
bool IsChromePotentiallyNoLongerDefaultBrowser(int likelyDefaultInterval,
                                               int likelyNotDefaultInterval);

// Returns true if the past behavior of the user indicates that the user fits
// the categorization that would likely benefit from having Chrome set as their
// default browser for the passed `type`. Returns false otherwise.
bool IsLikelyInterestedDefaultBrowserUser(DefaultPromoType type);

// Return YES if the user has seen a full screen promo recently, and shouldn't
// see another one.
bool UserInFullscreenPromoCooldown();

// Returns YES if the user has seen a non-modal promo recently, and shouldn't
// see another one.
bool UserInNonModalPromoCooldown();

// List of all key used to store data in NSUserDefaults. Still used as key
// in the NSDictionary stored under `kBrowserDefaultsKey`.
const NSArray<NSString*>* DefaultBrowserUtilsLegacyKeysForTesting();

// Returns the impression limit for the non-modal default browser promo.
int GetNonModalDefaultBrowserPromoImpressionLimit();

// Returns true if it was determined that the user is eligible for the
// post restore default browser promo.
bool IsPostRestoreDefaultBrowserEligibleUser();

// Converts Default browser promo type NSEnum to an enum that can be used by
// UMA.
DefaultPromoTypeForUMA GetDefaultPromoTypeForUMA(DefaultPromoType type);

// Log given default browser promo action to the UMA histogram coorespnding to
// the given promo type.
void LogDefaultBrowserPromoHistogramForAction(
    DefaultPromoType type,
    IOSDefaultBrowserPromoAction action);

// Below collect and compute data to record for an experiment. It is potentially
// a lot of data but this is planned as a short and small experiment.

// Returns string representation of the enum value.
const std::string IOSDefaultBrowserPromoActionToString(
    IOSDefaultBrowserPromoAction action);

// Returns PromoStatistics object with all properties calculated.
PromoStatistics* CalculatePromoStatistics();

// Records given promo stats for given action into UMA histograms.
void RecordPromoStatsToUMAForAction(PromoStatistics* promo_stats,
                                    IOSDefaultBrowserPromoAction action);

// Records given promo stats for "Appear" action into UMA histograms.
void RecordPromoStatsToUMAForAppear(PromoStatistics* promo_stats);

// Records stats related to promo display to UMA histograms.
void RecordPromoDisplayStatsToUMA();

// Logs browser launched for default browser promo trigger criteria experiment
// stats to NSUserDefaults. `LogBrowserIndirectlylaunched` and
// `LogBrowserLaunched` will have overlap.
void LogBrowserLaunched(bool is_cold_start);

// Log browser started indirectly(by widget or external url) for default browser
// promo experiment stats to NSUserDefaults. `LogBrowserIndirectlylaunched` and
// `LogBrowserLaunched` will have overlap.
void LogBrowserIndirectlylaunched();

// Migration to FET.

// Returns Default Browser FRE promo timestamp if it was the last default
// browser promo user seen. Otherwise, returns unix epoch.
base::Time GetDefaultBrowserFREPromoTimestampIfLast();

// Returns generic Default Browser timestamp if user seen a generic promo
// before. Otherwise, returns unix epoch.
base::Time GetGenericDefaultBrowserPromoTimestamp();

// Returns tailored Default Browser timestamp if user seen a tailored promo
// before. Otherwise, returns unix epoch.
base::Time GetTailoredDefaultBrowserPromoTimestamp();

// Log to UserDefaults FRE timestamp migration is done.
void LogFRETimestampMigrationDone();

// Returns whether FRE timestamp migratin is done.
BOOL FRETimestampMigrationDone();

// Log to UserDefaults promo interest event migration is done.
void LogPromoInterestEventMigrationDone();

// Returns whether promo interest event migratin is done.
BOOL IsPromoInterestEventMigrationDone();

// Log to UserDefaults promo impressions migration is done.
void LogPromoImpressionsMigrationDone();

// Returns whether promo impressions migratin is done.
BOOL IsPromoImpressionsMigrationDone();

// Records the last action the user took when a Default Browser Promo was
// presented.
void RecordDefaultBrowserPromoLastAction(IOSDefaultBrowserPromoAction action);

// Returns the last action, if any, that the user took when a Default Browser
// Promo was presented.
std::optional<IOSDefaultBrowserPromoAction> DefaultBrowserPromoLastAction();

#endif  // IOS_CHROME_BROWSER_DEFAULT_BROWSER_MODEL_UTILS_H_