blob: 30505b4d33d3524dacb6950955c5c73243d11cf8 [file] [log] [blame]
sdefresne14900ee2015-11-27 14:43:211// Copyright 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Implementation of about_flags for iOS that sets flags based on experimental
6// settings.
7
8#include "ios/chrome/browser/about_flags.h"
9
avi571943672015-12-22 02:12:4910#include <stddef.h>
11#include <stdint.h>
sdefresne14900ee2015-11-27 14:43:2112#import <UIKit/UIKit.h>
13
Gregory Chatzinofff6523722017-11-21 01:33:5314#include "base/base_switches.h"
sdefresne14900ee2015-11-27 14:43:2115#include "base/bind.h"
16#include "base/command_line.h"
17#include "base/logging.h"
avi571943672015-12-22 02:12:4918#include "base/macros.h"
sdefresne14900ee2015-11-27 14:43:2119#include "base/memory/singleton.h"
20#include "base/strings/stringprintf.h"
21#include "base/strings/sys_string_conversions.h"
22#include "base/sys_info.h"
robliao59eed1a2016-10-28 17:12:1623#include "base/task_scheduler/switches.h"
sdefresne14900ee2015-11-27 14:43:2124#include "components/dom_distiller/core/dom_distiller_switches.h"
Tommy Nyquistc1d6dea12017-07-26 20:37:2325#include "components/feature_engagement/public/feature_constants.h"
26#include "components/feature_engagement/public/feature_list.h"
sdefresne14900ee2015-11-27 14:43:2127#include "components/flags_ui/feature_entry.h"
28#include "components/flags_ui/feature_entry_macros.h"
29#include "components/flags_ui/flags_storage.h"
30#include "components/flags_ui/flags_ui_switches.h"
noyau4cfb1332016-10-25 17:05:4231#include "components/ntp_tiles/switches.h"
Justin Donnelly33d712e2017-08-23 21:32:5132#include "components/omnibox/browser/omnibox_field_trial.h"
mathp9b4c11d2017-07-06 20:24:1333#include "components/payments/core/features.h"
Marc Treib5fc99e1f2017-11-08 12:19:1834#include "components/search_provider_logos/switches.h"
elawrence816f6790e2017-06-16 18:19:2835#include "components/security_state/core/switches.h"
David Rogera6c88122017-10-25 13:02:4636#include "components/signin/core/browser/signin_switches.h"
sdefresne36579782016-02-05 11:08:2537#include "components/strings/grit/components_strings.h"
Marti Wong87d31d72017-08-25 02:44:5238#include "ios/chrome/browser/bookmarks/bookmark_new_generation_features.h"
sdefresne14900ee2015-11-27 14:43:2139#include "ios/chrome/browser/chrome_switches.h"
Jean-François Geyelin30be5912017-08-25 12:05:3840#include "ios/chrome/browser/drag_and_drop/drag_and_drop_flag.h"
vabr0215a8e2017-03-28 12:47:3441#include "ios/chrome/browser/ios_chrome_flag_descriptions.h"
Mike Doughertya5e5ad52017-08-05 00:11:5842#include "ios/chrome/browser/ssl/captive_portal_features.h"
Gregory Chatzinoff6f3a2602017-10-31 06:24:3543#include "ios/chrome/browser/ui/activity_services/canonical_url_feature.h"
Louis Romerod11747a2017-10-20 20:10:3544#include "ios/chrome/browser/ui/external_search/features.h"
Kurt Horimotoa5a922a2017-11-07 00:21:0945#include "ios/chrome/browser/ui/fullscreen/fullscreen_features.h"
sczsa0c91942017-10-26 18:39:5946#import "ios/chrome/browser/ui/history/history_base_feature.h"
Rohit Rao6a3a481d2017-09-25 19:31:4147#include "ios/chrome/browser/ui/main/main_feature_flags.h"
sczs6ca1d262017-10-30 20:27:1348#import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h"
Justin Cohenba27610e2017-11-08 19:34:4549#import "ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.h"
sdefresne14900ee2015-11-27 14:43:2150#include "ios/chrome/grit/ios_strings.h"
msardafc76f662017-02-24 12:46:2851#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
Danyao Wang34da6ff2017-10-30 15:16:5652#include "ios/web/public/features.h"
sdefresne14900ee2015-11-27 14:43:2153#include "ios/web/public/user_agent.h"
54#include "ios/web/public/web_view_creation_util.h"
55
56#if !defined(OFFICIAL_BUILD)
57#include "components/variations/variations_switches.h"
vitaliii489217aa2017-01-30 14:50:2258#endif
stkhapuginc1be1792016-12-13 14:30:5359
60#if !defined(__has_feature) || !__has_feature(objc_arc)
61#error "This file requires ARC support."
62#endif
sdefresne14900ee2015-11-27 14:43:2163
elawrence816f6790e2017-06-16 18:19:2864using flags_ui::FeatureEntry;
65
sdefresne14900ee2015-11-27 14:43:2166namespace {
elawrence816f6790e2017-06-16 18:19:2867const FeatureEntry::Choice kMarkHttpAsChoices[] = {
68 {flags_ui::kGenericExperimentChoiceDefault, "", ""},
elawrence816f6790e2017-06-16 18:19:2869 {flag_descriptions::kMarkHttpAsDangerous,
70 security_state::switches::kMarkHttpAs,
71 security_state::switches::kMarkHttpAsDangerous}};
72
Marc Treib5fc99e1f2017-11-08 12:19:1873const FeatureEntry::Choice kUseDdljsonApiChoices[] = {
74 {flags_ui::kGenericExperimentChoiceDefault, "", ""},
75 {"(force test doodle 0)", search_provider_logos::switches::kGoogleDoodleUrl,
76 "https://www.gstatic.com/chrome/ntp/doodle_test/ddljson_ios0.json"},
77 {"(force test doodle 1)", search_provider_logos::switches::kGoogleDoodleUrl,
78 "https://www.gstatic.com/chrome/ntp/doodle_test/ddljson_ios1.json"},
79 {"(force test doodle 2)", search_provider_logos::switches::kGoogleDoodleUrl,
80 "https://www.gstatic.com/chrome/ntp/doodle_test/ddljson_ios2.json"},
81 {"(force test doodle 3)", search_provider_logos::switches::kGoogleDoodleUrl,
82 "https://www.gstatic.com/chrome/ntp/doodle_test/ddljson_ios3.json"},
83 {"(force test doodle 4)", search_provider_logos::switches::kGoogleDoodleUrl,
84 "https://www.gstatic.com/chrome/ntp/doodle_test/ddljson_ios4.json"},
85};
Marc Treib2752e8b2017-08-04 14:12:0986
Cooper Knaak1e026562017-07-26 05:22:2887// To add a new entry, add to the end of kFeatureEntries. There are four
sdefresne14900ee2015-11-27 14:43:2188// distinct types of entries:
Cooper Knaak1e026562017-07-26 05:22:2889// . ENABLE_DISABLE_VALUE: entry is either enabled, disabled, or uses the
90// default value for this feature. Use the ENABLE_DISABLE_VALUE_TYPE
sdefresne14900ee2015-11-27 14:43:2191// macro for this type supplying the command line to the macro.
92// . MULTI_VALUE: a list of choices, the first of which should correspond to a
93// deactivated state for this lab (i.e. no command line option). To specify
94// this type of entry use the macro MULTI_VALUE_TYPE supplying it the
95// array of choices.
Cooper Knaak1e026562017-07-26 05:22:2896// . FEATURE_VALUE: entry is associated with a base::Feature instance. Entry is
97// either enabled, disabled, or uses the default value of the associated
98// base::Feature instance. To specify this type of entry use the macro
99// FEATURE_VALUE_TYPE supplying it the base::Feature instance.
100// . FEATURE_WITH_PARAM_VALUES: a list of choices associated with a
101// base::Feature instance. Choices corresponding to the default state, a
102// universally enabled state, and a universally disabled state are
103// automatically included. To specify this type of entry use the macro
104// FEATURE_WITH_PARAMS_VALUE_TYPE supplying it the base::Feature instance and
105// the array of choices.
106//
sdefresne14900ee2015-11-27 14:43:21107// See the documentation of FeatureEntry for details on the fields.
108//
109// When adding a new choice, add it to the end of the list.
110const flags_ui::FeatureEntry kFeatureEntries[] = {
vabr0215a8e2017-03-28 12:47:34111 {"contextual-search", flag_descriptions::kContextualSearch,
112 flag_descriptions::kContextualSearchDescription, flags_ui::kOsIos,
sdefresne14900ee2015-11-27 14:43:21113 ENABLE_DISABLE_VALUE_TYPE(switches::kEnableContextualSearch,
114 switches::kDisableContextualSearch)},
vabr0215a8e2017-03-28 12:47:34115 {"browser-task-scheduler", flag_descriptions::kBrowserTaskScheduler,
116 flag_descriptions::kBrowserTaskSchedulerDescription, flags_ui::kOsIos,
robliao59eed1a2016-10-28 17:12:16117 ENABLE_DISABLE_VALUE_TYPE(switches::kEnableBrowserTaskScheduler,
118 switches::kDisableBrowserTaskScheduler)},
elawrence816f6790e2017-06-16 18:19:28119 {"mark-non-secure-as", flag_descriptions::kMarkHttpAsName,
120 flag_descriptions::kMarkHttpAsDescription, flags_ui::kOsIos,
121 MULTI_VALUE_TYPE(kMarkHttpAsChoices)},
mathp9b4c11d2017-07-06 20:24:13122 {"web-payments", flag_descriptions::kWebPaymentsName,
123 flag_descriptions::kWebPaymentsDescription, flags_ui::kOsIos,
124 FEATURE_VALUE_TYPE(payments::features::kWebPayments)},
Randall Raymond59766ac2017-08-09 16:28:58125 {"web-payments-native-apps", flag_descriptions::kWebPaymentsNativeAppsName,
126 flag_descriptions::kWebPaymentsNativeAppsDescription, flags_ui::kOsIos,
127 FEATURE_VALUE_TYPE(payments::features::kWebPaymentsNativeApps)},
Mike Doughertya5e5ad52017-08-05 00:11:58128 {"ios-captive-portal", flag_descriptions::kCaptivePortalName,
129 flag_descriptions::kCaptivePortalDescription, flags_ui::kOsIos,
130 FEATURE_VALUE_TYPE(kCaptivePortalFeature)},
Cooper Knaak1e026562017-07-26 05:22:28131 {"in-product-help-demo-mode-choice",
132 flag_descriptions::kInProductHelpDemoModeName,
133 flag_descriptions::kInProductHelpDemoModeDescription, flags_ui::kOsIos,
134 FEATURE_WITH_PARAMS_VALUE_TYPE(
Tommy Nyquistc1d6dea12017-07-26 20:37:23135 feature_engagement::kIPHDemoMode,
136 feature_engagement::kIPHDemoModeChoiceVariations,
Marc Treib2752e8b2017-08-04 14:12:09137 "IPH_DemoMode")},
138 {"use-ddljson-api", flag_descriptions::kUseDdljsonApiName,
139 flag_descriptions::kUseDdljsonApiDescription, flags_ui::kOsIos,
Marc Treib5fc99e1f2017-11-08 12:19:18140 MULTI_VALUE_TYPE(kUseDdljsonApiChoices)},
Justin Donnelly33d712e2017-08-23 21:32:51141 {"omnibox-ui-elide-suggestion-url-after-host",
142 flag_descriptions::kOmniboxUIElideSuggestionUrlAfterHostName,
143 flag_descriptions::kOmniboxUIElideSuggestionUrlAfterHostDescription,
144 flags_ui::kOsIos,
145 FEATURE_VALUE_TYPE(omnibox::kUIExperimentElideSuggestionUrlAfterHost)},
146 {"omnibox-ui-hide-suggestion-url-scheme",
147 flag_descriptions::kOmniboxUIHideSuggestionUrlSchemeName,
148 flag_descriptions::kOmniboxUIHideSuggestionUrlSchemeDescription,
149 flags_ui::kOsIos,
150 FEATURE_VALUE_TYPE(omnibox::kUIExperimentHideSuggestionUrlScheme)},
151 {"omnibox-ui-hide-suggestion-url-trivial-subdomains",
152 flag_descriptions::kOmniboxUIHideSuggestionUrlTrivialSubdomainsName,
153 flag_descriptions::kOmniboxUIHideSuggestionUrlTrivialSubdomainsDescription,
154 flags_ui::kOsIos,
155 FEATURE_VALUE_TYPE(
Marti Wong87d31d72017-08-25 02:44:52156 omnibox::kUIExperimentHideSuggestionUrlTrivialSubdomains)},
157 {"bookmark-new-generation", flag_descriptions::kBookmarkNewGenerationName,
158 flag_descriptions::kBookmarkNewGenerationDescription, flags_ui::kOsIos,
Marti Wongf0f4dfb2017-09-01 11:24:39159 FEATURE_VALUE_TYPE(kBookmarkNewGeneration)},
Jean-François Geyelin30be5912017-08-25 12:05:38160#if defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0)
161 {"drag_and_drop", flag_descriptions::kDragAndDropName,
162 flag_descriptions::kDragAndDropDescription, flags_ui::kOsIos,
Rohit Rao6a3a481d2017-09-25 19:31:41163 FEATURE_VALUE_TYPE(kDragAndDrop)},
Jean-François Geyelin30be5912017-08-25 12:05:38164#endif
Rohit Rao6a3a481d2017-09-25 19:31:41165 {"tab_switcher_presents_bvc",
166 flag_descriptions::kTabSwitcherPresentsBVCName,
167 flag_descriptions::kTabSwitcherPresentsBVCDescription, flags_ui::kOsIos,
Jean-François Geyelined4cde72017-10-11 11:34:50168 FEATURE_VALUE_TYPE(kTabSwitcherPresentsBVC)},
169 {"safe_area_compatible_toolbar",
170 flag_descriptions::kSafeAreaCompatibleToolbarName,
171 flag_descriptions::kSafeAreaCompatibleToolbarDescription, flags_ui::kOsIos,
Louis Romerod11747a2017-10-20 20:10:35172 FEATURE_VALUE_TYPE(kSafeAreaCompatibleToolbar)},
173 {"external-search", flag_descriptions::kExternalSearchName,
174 flag_descriptions::kExternalSearchDescription, flags_ui::kOsIos,
175 FEATURE_VALUE_TYPE(kExternalSearch)},
sczsa0c91942017-10-26 18:39:59176 {"history-batch-updates-filter",
177 flag_descriptions::kHistoryBatchUpdatesFilterName,
178 flag_descriptions::kHistoryBatchUpdatesFilterDescription, flags_ui::kOsIos,
179 FEATURE_VALUE_TYPE(kHistoryBatchUpdatesFilter)},
Danyao Wang34da6ff2017-10-30 15:16:56180 {"slim-navigation-manager", flag_descriptions::kSlimNavigationManagerName,
181 flag_descriptions::kSlimNavigationManagerDescription, flags_ui::kOsIos,
182 FEATURE_VALUE_TYPE(web::features::kSlimNavigationManager)},
Gregory Chatzinoff6f3a2602017-10-31 06:24:35183 {"ios-share-canonical-url", flag_descriptions::kShareCanonicalURLName,
184 flag_descriptions::kShareCanonicalURLDescription, flags_ui::kOsIos,
185 FEATURE_VALUE_TYPE(activity_services::kShareCanonicalURL)},
sczs9a142dc2017-10-31 23:34:06186 {"property-animations-toolbar",
187 flag_descriptions::kPropertyAnimationsToolbarName,
188 flag_descriptions::kPropertyAnimationsToolbarDescription, flags_ui::kOsIos,
Gauthier Ambardba34b462017-11-06 09:06:42189 FEATURE_VALUE_TYPE(kPropertyAnimationsToolbar)},
Kurt Horimotoa5a922a2017-11-07 00:21:09190 {"new-fullscreen-controller", flag_descriptions::kNewFullscreenName,
191 flag_descriptions::kNewFullscreenDescription, flags_ui::kOsIos,
Gauthier Ambardccc4c682017-11-17 15:36:37192 FEATURE_VALUE_TYPE(fullscreen::features::kNewFullscreen)},
193 {"clean-toolbar", flag_descriptions::kCleanToolbarName,
194 flag_descriptions::kCleanToolbarDescription, flags_ui::kOsIos,
195 FEATURE_VALUE_TYPE(kCleanToolbar)}};
sdefresne14900ee2015-11-27 14:43:21196
197// Add all switches from experimental flags to |command_line|.
198void AppendSwitchesFromExperimentalSettings(base::CommandLine* command_line) {
199 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
200
sdefresne14900ee2015-11-27 14:43:21201 // Web page replay flags.
202 BOOL webPageReplayEnabled = [defaults boolForKey:@"WebPageReplayEnabled"];
203 NSString* webPageReplayProxy =
204 [defaults stringForKey:@"WebPageReplayProxyAddress"];
205 if (webPageReplayEnabled && [webPageReplayProxy length]) {
206 command_line->AppendSwitch(switches::kIOSIgnoreCertificateErrors);
207 // 80 and 443 are the default ports from web page replay.
208 command_line->AppendSwitchASCII(switches::kIOSTestingFixedHttpPort, "80");
209 command_line->AppendSwitchASCII(switches::kIOSTestingFixedHttpsPort, "443");
210 command_line->AppendSwitchASCII(
211 switches::kIOSHostResolverRules,
212 "MAP * " + base::SysNSStringToUTF8(webPageReplayProxy));
213 }
214
sdefresne14900ee2015-11-27 14:43:21215 // Set the UA flag if UseMobileSafariUA is enabled.
216 if ([defaults boolForKey:@"UseMobileSafariUA"]) {
217 // Safari uses "Vesion/", followed by the OS version excluding bugfix, where
218 // Chrome puts its product token.
avi571943672015-12-22 02:12:49219 int32_t major = 0;
220 int32_t minor = 0;
221 int32_t bugfix = 0;
sdefresne14900ee2015-11-27 14:43:21222 base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
223 std::string product = base::StringPrintf("Version/%d.%d", major, minor);
224
225 command_line->AppendSwitchASCII(switches::kUserAgent,
226 web::BuildUserAgentFromProduct(product));
227 }
228
jkrcal7d79de52017-05-05 18:13:10229 // Populate command line flag for fetching missing favicons for NTP tiles.
230 NSString* enableMostLikelyFaviconsFromServer =
231 [defaults stringForKey:@"EnableNtpMostLikelyFaviconsFromServer"];
232 if ([enableMostLikelyFaviconsFromServer isEqualToString:@"Enabled"]) {
233 command_line->AppendSwitch(
234 ntp_tiles::switches::kEnableNtpMostLikelyFaviconsFromServer);
235 } else if ([enableMostLikelyFaviconsFromServer isEqualToString:@"Disabled"]) {
236 command_line->AppendSwitch(
237 ntp_tiles::switches::kDisableNtpMostLikelyFaviconsFromServer);
238 }
239
sdefresne14900ee2015-11-27 14:43:21240 // Freeform commandline flags. These are added last, so that any flags added
241 // earlier in this function take precedence.
242 if ([defaults boolForKey:@"EnableFreeformCommandLineFlags"]) {
243 base::CommandLine::StringVector flags;
244 // Append an empty "program" argument.
245 flags.push_back("");
246
247 // The number of flags corresponds to the number of text fields in
248 // Experimental.plist.
249 const int kNumFreeformFlags = 5;
250 for (int i = 1; i <= kNumFreeformFlags; ++i) {
251 NSString* key =
252 [NSString stringWithFormat:@"FreeformCommandLineFlag%d", i];
253 NSString* flag = [defaults stringForKey:key];
254 if ([flag length]) {
255 flags.push_back(base::SysNSStringToUTF8(flag));
256 }
257 }
258
259 base::CommandLine temp_command_line(flags);
260 command_line->AppendArguments(temp_command_line, false);
261 }
msardafc76f662017-02-24 12:46:28262
justincohendacc85d2017-06-28 23:34:10263 // Populate command line flag for 3rd party keyboard omnibox workaround.
264 NSString* enableThirdPartyKeyboardWorkaround =
265 [defaults stringForKey:@"EnableThirdPartyKeyboardWorkaround"];
266 if ([enableThirdPartyKeyboardWorkaround isEqualToString:@"Enabled"]) {
267 command_line->AppendSwitch(switches::kEnableThirdPartyKeyboardWorkaround);
268 } else if ([enableThirdPartyKeyboardWorkaround isEqualToString:@"Disabled"]) {
269 command_line->AppendSwitch(switches::kDisableThirdPartyKeyboardWorkaround);
270 }
271
msardafc76f662017-02-24 12:46:28272 ios::GetChromeBrowserProvider()->AppendSwitchesFromExperimentalSettings(
273 defaults, command_line);
sdefresne14900ee2015-11-27 14:43:21274}
275
276bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
277 return false;
278}
279
280class FlagsStateSingleton {
281 public:
282 FlagsStateSingleton()
283 : flags_state_(kFeatureEntries, arraysize(kFeatureEntries)) {}
284 ~FlagsStateSingleton() {}
285
286 static FlagsStateSingleton* GetInstance() {
287 return base::Singleton<FlagsStateSingleton>::get();
288 }
289
290 static flags_ui::FlagsState* GetFlagsState() {
291 return &GetInstance()->flags_state_;
292 }
293
294 private:
295 flags_ui::FlagsState flags_state_;
296
297 DISALLOW_COPY_AND_ASSIGN(FlagsStateSingleton);
298};
299} // namespace
300
301void ConvertFlagsToSwitches(flags_ui::FlagsStorage* flags_storage,
302 base::CommandLine* command_line) {
303 FlagsStateSingleton::GetFlagsState()->ConvertFlagsToSwitches(
sdefresnec9763902015-12-02 10:30:11304 flags_storage, command_line, flags_ui::kAddSentinels,
Gregory Chatzinofff6523722017-11-21 01:33:53305 switches::kEnableFeatures, switches::kDisableFeatures);
sdefresne14900ee2015-11-27 14:43:21306 AppendSwitchesFromExperimentalSettings(command_line);
307}
308
jkrcalbf073372016-07-29 07:21:31309std::vector<std::string> RegisterAllFeatureVariationParameters(
310 flags_ui::FlagsStorage* flags_storage,
311 base::FeatureList* feature_list) {
312 return FlagsStateSingleton::GetFlagsState()
313 ->RegisterAllFeatureVariationParameters(flags_storage, feature_list);
314}
315
sdefresne14900ee2015-11-27 14:43:21316void GetFlagFeatureEntries(flags_ui::FlagsStorage* flags_storage,
317 flags_ui::FlagAccess access,
318 base::ListValue* supported_entries,
319 base::ListValue* unsupported_entries) {
320 FlagsStateSingleton::GetFlagsState()->GetFlagFeatureEntries(
321 flags_storage, access, supported_entries, unsupported_entries,
322 base::Bind(&SkipConditionalFeatureEntry));
323}
324
325void SetFeatureEntryEnabled(flags_ui::FlagsStorage* flags_storage,
326 const std::string& internal_name,
327 bool enable) {
328 FlagsStateSingleton::GetFlagsState()->SetFeatureEntryEnabled(
329 flags_storage, internal_name, enable);
330}
331
332void ResetAllFlags(flags_ui::FlagsStorage* flags_storage) {
333 FlagsStateSingleton::GetFlagsState()->ResetAllFlags(flags_storage);
334}
335
336namespace testing {
337
338const flags_ui::FeatureEntry* GetFeatureEntries(size_t* count) {
339 *count = arraysize(kFeatureEntries);
340 return kFeatureEntries;
341}
342
343} // namespace testing