blob: ca2070b7eba432ec91ad1e8ecd721d9cbebbab5e [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ntp/features.h"
#import <Foundation/Foundation.h>
#import "base/metrics/field_trial_params.h"
#import "components/version_info/channel.h"
#import "ios/chrome/app/background_mode_buildflags.h"
#import "ios/chrome/browser/shared/public/features/system_flags.h"
#import "ios/chrome/common/channel_info.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// Whether feed background refresh is enabled. This only checks if the feature
// is enabled, not if the capability was enabled at startup.
bool IsFeedBackgroundRefreshEnabledOnly() {
return base::FeatureList::IsEnabled(kEnableFeedBackgroundRefresh);
}
// Whether feed is refreshed in the background soon after the app is
// backgrounded. This only checks if the feature is enabled, not if the
// capability was enabled at startup.
bool IsFeedAppCloseBackgroundRefreshEnabledOnly() {
return base::GetFieldTrialParamByFeatureAsBool(
kEnableFeedInvisibleForegroundRefresh,
kEnableFeedAppCloseBackgroundRefresh,
/*default=*/false);
}
// Returns the override value from the Foreground Refresh section of Feed
// Refresh Settings in Experimental Settings in the Settings App.
bool IsFeedOverrideForegroundDefaultsEnabled() {
if (GetChannel() == version_info::Channel::STABLE) {
return false;
}
return [[NSUserDefaults standardUserDefaults]
boolForKey:@"FeedOverrideForegroundDefaultsEnabled"];
}
} // namespace
BASE_FEATURE(kEnableWebChannels,
"EnableWebChannels",
base::FEATURE_DISABLED_BY_DEFAULT);
BASE_FEATURE(kEnableFeedBackgroundRefresh,
"EnableFeedBackgroundRefresh",
base::FEATURE_DISABLED_BY_DEFAULT);
BASE_FEATURE(kEnableFeedInvisibleForegroundRefresh,
"EnableFeedInvisibleForegroundRefresh",
base::FEATURE_DISABLED_BY_DEFAULT);
BASE_FEATURE(kCreateDiscoverFeedServiceEarly,
"CreateDiscoverFeedServiceEarly",
base::FEATURE_DISABLED_BY_DEFAULT);
BASE_FEATURE(kEnableFeedBottomSignInPromo,
"EnableFeedBottomSignInPromo",
base::FEATURE_ENABLED_BY_DEFAULT);
BASE_FEATURE(kEnableFeedCardMenuSignInPromo,
"EnableFeedCardMenuSignInPromo",
base::FEATURE_DISABLED_BY_DEFAULT);
BASE_FEATURE(kEnableFeedAblation,
"EnableFeedAblation",
base::FEATURE_DISABLED_BY_DEFAULT);
BASE_FEATURE(kEnableFeedExperimentTagging,
"EnableFeedExperimentTagging",
base::FEATURE_ENABLED_BY_DEFAULT);
BASE_FEATURE(kIOSSetUpList, "IOSSetUpList", base::FEATURE_DISABLED_BY_DEFAULT);
BASE_FEATURE(kFeedDisableHotStartRefresh,
"FeedDisableHotStartRefresh",
base::FEATURE_DISABLED_BY_DEFAULT);
BASE_FEATURE(kEnableFollowUIUpdate,
"EnableFollowUIUpdate",
base::FEATURE_ENABLED_BY_DEFAULT);
// Key for NSUserDefaults containing a bool indicating whether the next run
// should enable feed background refresh capability. This is used because
// registering for background refreshes must happen early in app initialization
// and FeatureList is not yet available. Enabling or disabling background
// refresh features will always take effect after two cold starts after the
// feature has been changed on the server (once for the Finch configuration, and
// another for reading the stored value from NSUserDefaults).
NSString* const kEnableFeedBackgroundRefreshCapabilityForNextColdStart =
@"EnableFeedBackgroundRefreshCapabilityForNextColdStart";
const char kEnableFollowingFeedBackgroundRefresh[] =
"EnableFollowingFeedBackgroundRefresh";
const char kEnableServerDrivenBackgroundRefreshSchedule[] =
"EnableServerDrivenBackgroundRefreshSchedule";
const char kEnableRecurringBackgroundRefreshSchedule[] =
"EnableRecurringBackgroundRefreshSchedule";
const char kMaxCacheAgeInSeconds[] = "MaxCacheAgeInSeconds";
const char kBackgroundRefreshIntervalInSeconds[] =
"BackgroundRefreshIntervalInSeconds";
const char kBackgroundRefreshMaxAgeInSeconds[] =
"BackgroundRefreshMaxAgeInSeconds";
const char kEnableFeedSessionCloseForegroundRefresh[] =
"EnableFeedSessionCloseForegroundRefresh";
const char kEnableFeedAppCloseForegroundRefresh[] =
"EnableFeedAppCloseForegroundRefresh";
const char kEnableFeedAppCloseBackgroundRefresh[] =
"EnableFeedAppCloseBackgroundRefresh";
const char kFeedRefreshEngagementCriteriaType[] =
"FeedRefreshEngagementCriteriaType";
const char kAppCloseBackgroundRefreshIntervalInSeconds[] =
"AppCloseBackgroundRefreshIntervalInSeconds";
const char kFeedRefreshTimerTimeoutInSeconds[] =
"FeedRefreshTimerTimeoutInSeconds";
const char kFeedSeenRefreshThresholdInSeconds[] =
"FeedSeenRefreshThresholdInSeconds";
const char kFeedUnseenRefreshThresholdInSeconds[] =
"FeedUnseenRefreshThresholdInSeconds";
const char kEnableFeedUseInteractivityInvalidationForForegroundRefreshes[] =
"EnableFeedUseInteractivityInvalidationForForegroundRefreshes";
bool IsWebChannelsEnabled() {
return base::FeatureList::IsEnabled(kEnableWebChannels);
}
bool IsDiscoverFeedServiceCreatedEarly() {
return base::FeatureList::IsEnabled(kCreateDiscoverFeedServiceEarly);
}
bool IsFeedBackgroundRefreshEnabled() {
return IsFeedBackgroundRefreshCapabilityEnabled() &&
IsFeedBackgroundRefreshEnabledOnly();
}
bool IsFeedBackgroundRefreshCapabilityEnabled() {
#if !BUILDFLAG(IOS_BACKGROUND_MODE_ENABLED)
return false;
#else
static bool feedBackgroundRefreshEnabled =
[[NSUserDefaults standardUserDefaults]
boolForKey:kEnableFeedBackgroundRefreshCapabilityForNextColdStart];
return feedBackgroundRefreshEnabled;
#endif // BUILDFLAG(IOS_BACKGROUND_MODE_ENABLED)
}
void SaveFeedBackgroundRefreshCapabilityEnabledForNextColdStart() {
DCHECK(base::FeatureList::GetInstance());
BOOL enabled = IsFeedBackgroundRefreshEnabledOnly() ||
IsFeedAppCloseBackgroundRefreshEnabledOnly();
[[NSUserDefaults standardUserDefaults]
setBool:enabled
forKey:kEnableFeedBackgroundRefreshCapabilityForNextColdStart];
}
void SetFeedRefreshTimestamp(NSDate* timestamp, NSString* NSUserDefaultsKey) {
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateStyle = NSDateFormatterShortStyle;
dateFormatter.timeStyle = NSDateFormatterShortStyle;
dateFormatter.locale = [NSLocale autoupdatingCurrentLocale];
[[NSUserDefaults standardUserDefaults]
setObject:[dateFormatter stringFromDate:timestamp]
forKey:NSUserDefaultsKey];
}
bool IsFeedOverrideDefaultsEnabled() {
if (GetChannel() == version_info::Channel::STABLE) {
return false;
}
return [[NSUserDefaults standardUserDefaults]
boolForKey:@"FeedOverrideDefaultsEnabled"];
}
bool IsFeedBackgroundRefreshCompletedNotificationEnabled() {
if (GetChannel() == version_info::Channel::STABLE) {
return false;
}
return IsFeedBackgroundRefreshCapabilityEnabled() &&
[[NSUserDefaults standardUserDefaults]
boolForKey:@"FeedBackgroundRefreshNotificationEnabled"];
}
bool IsFollowingFeedBackgroundRefreshEnabled() {
if (IsFeedOverrideDefaultsEnabled()) {
return [[NSUserDefaults standardUserDefaults]
boolForKey:@"FollowingFeedBackgroundRefreshEnabled"];
}
return base::GetFieldTrialParamByFeatureAsBool(
kEnableFeedBackgroundRefresh, kEnableFollowingFeedBackgroundRefresh,
/*default=*/false);
}
bool IsServerDrivenBackgroundRefreshScheduleEnabled() {
if (IsFeedOverrideDefaultsEnabled()) {
return [[NSUserDefaults standardUserDefaults]
boolForKey:@"FeedServerDrivenBackgroundRefreshScheduleEnabled"];
}
return base::GetFieldTrialParamByFeatureAsBool(
kEnableFeedBackgroundRefresh,
kEnableServerDrivenBackgroundRefreshSchedule, /*default=*/false);
}
bool IsRecurringBackgroundRefreshScheduleEnabled() {
if (IsFeedOverrideDefaultsEnabled()) {
return [[NSUserDefaults standardUserDefaults]
boolForKey:@"FeedRecurringBackgroundRefreshScheduleEnabled"];
}
return base::GetFieldTrialParamByFeatureAsBool(
kEnableFeedBackgroundRefresh, kEnableRecurringBackgroundRefreshSchedule,
/*default=*/false);
}
double GetFeedMaxCacheAgeInSeconds() {
if (IsFeedOverrideDefaultsEnabled()) {
return [[NSUserDefaults standardUserDefaults]
doubleForKey:@"FeedMaxCacheAgeInSeconds"];
}
return base::GetFieldTrialParamByFeatureAsDouble(kEnableFeedBackgroundRefresh,
kMaxCacheAgeInSeconds,
/*default=*/8 * 60 * 60);
}
double GetBackgroundRefreshIntervalInSeconds() {
if (IsFeedOverrideDefaultsEnabled()) {
return [[NSUserDefaults standardUserDefaults]
doubleForKey:@"FeedBackgroundRefreshIntervalInSeconds"];
}
return base::GetFieldTrialParamByFeatureAsDouble(
kEnableFeedBackgroundRefresh, kBackgroundRefreshIntervalInSeconds,
/*default=*/60 * 60);
}
double GetBackgroundRefreshMaxAgeInSeconds() {
return base::GetFieldTrialParamByFeatureAsDouble(
kEnableFeedBackgroundRefresh, kBackgroundRefreshMaxAgeInSeconds,
/*default=*/0);
}
bool IsFeedInvisibleForegroundRefreshEnabled() {
return base::FeatureList::IsEnabled(kEnableFeedInvisibleForegroundRefresh);
}
bool IsFeedSessionCloseForegroundRefreshEnabled() {
return base::GetFieldTrialParamByFeatureAsBool(
kEnableFeedInvisibleForegroundRefresh,
kEnableFeedSessionCloseForegroundRefresh,
/*default=*/false);
}
bool IsFeedAppCloseForegroundRefreshEnabled() {
return base::GetFieldTrialParamByFeatureAsBool(
kEnableFeedInvisibleForegroundRefresh,
kEnableFeedAppCloseForegroundRefresh,
/*default=*/false);
}
bool IsFeedAppCloseBackgroundRefreshEnabled() {
return IsFeedBackgroundRefreshCapabilityEnabled() &&
IsFeedAppCloseBackgroundRefreshEnabledOnly();
}
FeedRefreshEngagementCriteriaType GetFeedRefreshEngagementCriteriaType() {
return (FeedRefreshEngagementCriteriaType)
base::GetFieldTrialParamByFeatureAsInt(
kEnableFeedInvisibleForegroundRefresh,
kFeedRefreshEngagementCriteriaType,
/*default_value=*/
(int)FeedRefreshEngagementCriteriaType::kSimpleEngagement);
}
double GetAppCloseBackgroundRefreshIntervalInSeconds() {
double override_value = [[NSUserDefaults standardUserDefaults]
doubleForKey:@"AppCloseBackgroundRefreshIntervalInSeconds"];
if (override_value > 0.0) {
return override_value;
}
return base::GetFieldTrialParamByFeatureAsDouble(
kEnableFeedInvisibleForegroundRefresh,
kAppCloseBackgroundRefreshIntervalInSeconds,
/*default=*/base::Minutes(5).InSecondsF());
}
double GetFeedRefreshTimerTimeoutInSeconds() {
double override_value = [[NSUserDefaults standardUserDefaults]
doubleForKey:@"FeedRefreshTimerTimeoutInSeconds"];
if (override_value > 0.0) {
return override_value;
}
return base::GetFieldTrialParamByFeatureAsDouble(
kEnableFeedInvisibleForegroundRefresh, kFeedRefreshTimerTimeoutInSeconds,
/*default=*/base::Minutes(5).InSecondsF());
}
double GetFeedSeenRefreshThresholdInSeconds() {
double override_value = [[NSUserDefaults standardUserDefaults]
doubleForKey:@"FeedSeenRefreshThresholdInSeconds"];
if (override_value > 0.0) {
return override_value;
}
return base::GetFieldTrialParamByFeatureAsDouble(
kEnableFeedInvisibleForegroundRefresh, kFeedSeenRefreshThresholdInSeconds,
/*default=*/base::Hours(1).InSecondsF());
}
double GetFeedUnseenRefreshThresholdInSeconds() {
double override_value = [[NSUserDefaults standardUserDefaults]
doubleForKey:@"FeedUnseenRefreshThresholdInSeconds"];
if (override_value > 0.0) {
return override_value;
}
return base::GetFieldTrialParamByFeatureAsDouble(
kEnableFeedInvisibleForegroundRefresh,
kFeedUnseenRefreshThresholdInSeconds,
/*default=*/base::Hours(6).InSecondsF());
}
bool IsFeedUseInteractivityInvalidationForForegroundRefreshesEnabled() {
if (IsFeedOverrideForegroundDefaultsEnabled()) {
return [[NSUserDefaults standardUserDefaults]
doubleForKey:
@"FeedUseInteractivityInvalidationForForegroundRefreshesEnabled"];
}
return base::GetFieldTrialParamByFeatureAsBool(
kEnableFeedInvisibleForegroundRefresh,
kEnableFeedUseInteractivityInvalidationForForegroundRefreshes,
/*default=*/false);
}
bool IsFeedBottomSignInPromoEnabled() {
return base::FeatureList::IsEnabled(kEnableFeedBottomSignInPromo);
}
bool IsFeedCardMenuSignInPromoEnabled() {
return base::FeatureList::IsEnabled(kEnableFeedCardMenuSignInPromo);
}
bool IsFeedAblationEnabled() {
return base::FeatureList::IsEnabled(kEnableFeedAblation);
}
bool IsFeedExperimentTaggingEnabled() {
return base::FeatureList::IsEnabled(kEnableFeedExperimentTagging);
}
bool IsIOSSetUpListEnabled() {
return base::FeatureList::IsEnabled(kIOSSetUpList);
}
bool IsFeedHotStartRefreshDisabled() {
return base::FeatureList::IsEnabled(kFeedDisableHotStartRefresh);
}
bool IsFollowUIUpdateEnabled() {
return base::FeatureList::IsEnabled(kEnableFollowUIUpdate);
}