blob: c3109d9fcd4ec228bc46fdb77f7a1cb13b337d40 [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
14#include "base/bind.h"
15#include "base/command_line.h"
16#include "base/logging.h"
avi571943672015-12-22 02:12:4917#include "base/macros.h"
sdefresne14900ee2015-11-27 14:43:2118#include "base/memory/singleton.h"
19#include "base/strings/stringprintf.h"
20#include "base/strings/sys_string_conversions.h"
21#include "base/sys_info.h"
robliao59eed1a2016-10-28 17:12:1622#include "base/task_scheduler/switches.h"
sdefresne14900ee2015-11-27 14:43:2123#include "components/dom_distiller/core/dom_distiller_switches.h"
Tommy Nyquistc1d6dea12017-07-26 20:37:2324#include "components/feature_engagement/public/feature_constants.h"
25#include "components/feature_engagement/public/feature_list.h"
sdefresne14900ee2015-11-27 14:43:2126#include "components/flags_ui/feature_entry.h"
27#include "components/flags_ui/feature_entry_macros.h"
28#include "components/flags_ui/flags_storage.h"
29#include "components/flags_ui/flags_ui_switches.h"
noyau4cfb1332016-10-25 17:05:4230#include "components/ntp_tiles/switches.h"
Justin Donnelly33d712e2017-08-23 21:32:5131#include "components/omnibox/browser/omnibox_field_trial.h"
mathp9b4c11d2017-07-06 20:24:1332#include "components/payments/core/features.h"
Marc Treib5fc99e1f2017-11-08 12:19:1833#include "components/search_provider_logos/switches.h"
elawrence816f6790e2017-06-16 18:19:2834#include "components/security_state/core/switches.h"
David Rogera6c88122017-10-25 13:02:4635#include "components/signin/core/browser/signin_switches.h"
sdefresne36579782016-02-05 11:08:2536#include "components/strings/grit/components_strings.h"
Marti Wong87d31d72017-08-25 02:44:5237#include "ios/chrome/browser/bookmarks/bookmark_new_generation_features.h"
sdefresne14900ee2015-11-27 14:43:2138#include "ios/chrome/browser/chrome_switches.h"
Jean-François Geyelin30be5912017-08-25 12:05:3839#include "ios/chrome/browser/drag_and_drop/drag_and_drop_flag.h"
vabr0215a8e2017-03-28 12:47:3440#include "ios/chrome/browser/ios_chrome_flag_descriptions.h"
Mike Doughertya5e5ad52017-08-05 00:11:5841#include "ios/chrome/browser/ssl/captive_portal_features.h"
Gregory Chatzinoff6f3a2602017-10-31 06:24:3542#include "ios/chrome/browser/ui/activity_services/canonical_url_feature.h"
Louis Romerod11747a2017-10-20 20:10:3543#include "ios/chrome/browser/ui/external_search/features.h"
Kurt Horimotoa5a922a2017-11-07 00:21:0944#include "ios/chrome/browser/ui/fullscreen/fullscreen_features.h"
sczsa0c91942017-10-26 18:39:5945#import "ios/chrome/browser/ui/history/history_base_feature.h"
Rohit Rao6a3a481d2017-09-25 19:31:4146#include "ios/chrome/browser/ui/main/main_feature_flags.h"
sczs6ca1d262017-10-30 20:27:1347#import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h"
Justin Cohenba27610e2017-11-08 19:34:4548#import "ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.h"
sdefresne14900ee2015-11-27 14:43:2149#include "ios/chrome/grit/ios_strings.h"
msardafc76f662017-02-24 12:46:2850#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
Danyao Wang34da6ff2017-10-30 15:16:5651#include "ios/web/public/features.h"
sdefresne14900ee2015-11-27 14:43:2152#include "ios/web/public/user_agent.h"
53#include "ios/web/public/web_view_creation_util.h"
54
55#if !defined(OFFICIAL_BUILD)
56#include "components/variations/variations_switches.h"
vitaliii489217aa2017-01-30 14:50:2257#endif
stkhapuginc1be1792016-12-13 14:30:5358
59#if !defined(__has_feature) || !__has_feature(objc_arc)
60#error "This file requires ARC support."
61#endif
sdefresne14900ee2015-11-27 14:43:2162
elawrence816f6790e2017-06-16 18:19:2863using flags_ui::FeatureEntry;
64
sdefresne14900ee2015-11-27 14:43:2165namespace {
elawrence816f6790e2017-06-16 18:19:2866const FeatureEntry::Choice kMarkHttpAsChoices[] = {
67 {flags_ui::kGenericExperimentChoiceDefault, "", ""},
elawrence816f6790e2017-06-16 18:19:2868 {flag_descriptions::kMarkHttpAsDangerous,
69 security_state::switches::kMarkHttpAs,
70 security_state::switches::kMarkHttpAsDangerous}};
71
Marc Treib5fc99e1f2017-11-08 12:19:1872const FeatureEntry::Choice kUseDdljsonApiChoices[] = {
73 {flags_ui::kGenericExperimentChoiceDefault, "", ""},
74 {"(force test doodle 0)", search_provider_logos::switches::kGoogleDoodleUrl,
75 "https://www.gstatic.com/chrome/ntp/doodle_test/ddljson_ios0.json"},
76 {"(force test doodle 1)", search_provider_logos::switches::kGoogleDoodleUrl,
77 "https://www.gstatic.com/chrome/ntp/doodle_test/ddljson_ios1.json"},
78 {"(force test doodle 2)", search_provider_logos::switches::kGoogleDoodleUrl,
79 "https://www.gstatic.com/chrome/ntp/doodle_test/ddljson_ios2.json"},
80 {"(force test doodle 3)", search_provider_logos::switches::kGoogleDoodleUrl,
81 "https://www.gstatic.com/chrome/ntp/doodle_test/ddljson_ios3.json"},
82 {"(force test doodle 4)", search_provider_logos::switches::kGoogleDoodleUrl,
83 "https://www.gstatic.com/chrome/ntp/doodle_test/ddljson_ios4.json"},
84};
Marc Treib2752e8b2017-08-04 14:12:0985
Cooper Knaak1e026562017-07-26 05:22:2886// To add a new entry, add to the end of kFeatureEntries. There are four
sdefresne14900ee2015-11-27 14:43:2187// distinct types of entries:
Cooper Knaak1e026562017-07-26 05:22:2888// . ENABLE_DISABLE_VALUE: entry is either enabled, disabled, or uses the
89// default value for this feature. Use the ENABLE_DISABLE_VALUE_TYPE
sdefresne14900ee2015-11-27 14:43:2190// macro for this type supplying the command line to the macro.
91// . MULTI_VALUE: a list of choices, the first of which should correspond to a
92// deactivated state for this lab (i.e. no command line option). To specify
93// this type of entry use the macro MULTI_VALUE_TYPE supplying it the
94// array of choices.
Cooper Knaak1e026562017-07-26 05:22:2895// . FEATURE_VALUE: entry is associated with a base::Feature instance. Entry is
96// either enabled, disabled, or uses the default value of the associated
97// base::Feature instance. To specify this type of entry use the macro
98// FEATURE_VALUE_TYPE supplying it the base::Feature instance.
99// . FEATURE_WITH_PARAM_VALUES: a list of choices associated with a
100// base::Feature instance. Choices corresponding to the default state, a
101// universally enabled state, and a universally disabled state are
102// automatically included. To specify this type of entry use the macro
103// FEATURE_WITH_PARAMS_VALUE_TYPE supplying it the base::Feature instance and
104// the array of choices.
105//
sdefresne14900ee2015-11-27 14:43:21106// See the documentation of FeatureEntry for details on the fields.
107//
108// When adding a new choice, add it to the end of the list.
109const flags_ui::FeatureEntry kFeatureEntries[] = {
vabr0215a8e2017-03-28 12:47:34110 {"contextual-search", flag_descriptions::kContextualSearch,
111 flag_descriptions::kContextualSearchDescription, flags_ui::kOsIos,
sdefresne14900ee2015-11-27 14:43:21112 ENABLE_DISABLE_VALUE_TYPE(switches::kEnableContextualSearch,
113 switches::kDisableContextualSearch)},
vabr0215a8e2017-03-28 12:47:34114 {"browser-task-scheduler", flag_descriptions::kBrowserTaskScheduler,
115 flag_descriptions::kBrowserTaskSchedulerDescription, flags_ui::kOsIos,
robliao59eed1a2016-10-28 17:12:16116 ENABLE_DISABLE_VALUE_TYPE(switches::kEnableBrowserTaskScheduler,
117 switches::kDisableBrowserTaskScheduler)},
elawrence816f6790e2017-06-16 18:19:28118 {"mark-non-secure-as", flag_descriptions::kMarkHttpAsName,
119 flag_descriptions::kMarkHttpAsDescription, flags_ui::kOsIos,
120 MULTI_VALUE_TYPE(kMarkHttpAsChoices)},
mathp9b4c11d2017-07-06 20:24:13121 {"web-payments", flag_descriptions::kWebPaymentsName,
122 flag_descriptions::kWebPaymentsDescription, flags_ui::kOsIos,
123 FEATURE_VALUE_TYPE(payments::features::kWebPayments)},
Randall Raymond59766ac2017-08-09 16:28:58124 {"web-payments-native-apps", flag_descriptions::kWebPaymentsNativeAppsName,
125 flag_descriptions::kWebPaymentsNativeAppsDescription, flags_ui::kOsIos,
126 FEATURE_VALUE_TYPE(payments::features::kWebPaymentsNativeApps)},
Mike Doughertya5e5ad52017-08-05 00:11:58127 {"ios-captive-portal", flag_descriptions::kCaptivePortalName,
128 flag_descriptions::kCaptivePortalDescription, flags_ui::kOsIos,
129 FEATURE_VALUE_TYPE(kCaptivePortalFeature)},
Cooper Knaak1e026562017-07-26 05:22:28130 {"in-product-help-demo-mode-choice",
131 flag_descriptions::kInProductHelpDemoModeName,
132 flag_descriptions::kInProductHelpDemoModeDescription, flags_ui::kOsIos,
133 FEATURE_WITH_PARAMS_VALUE_TYPE(
Tommy Nyquistc1d6dea12017-07-26 20:37:23134 feature_engagement::kIPHDemoMode,
135 feature_engagement::kIPHDemoModeChoiceVariations,
Marc Treib2752e8b2017-08-04 14:12:09136 "IPH_DemoMode")},
137 {"use-ddljson-api", flag_descriptions::kUseDdljsonApiName,
138 flag_descriptions::kUseDdljsonApiDescription, flags_ui::kOsIos,
Marc Treib5fc99e1f2017-11-08 12:19:18139 MULTI_VALUE_TYPE(kUseDdljsonApiChoices)},
Justin Donnelly33d712e2017-08-23 21:32:51140 {"omnibox-ui-elide-suggestion-url-after-host",
141 flag_descriptions::kOmniboxUIElideSuggestionUrlAfterHostName,
142 flag_descriptions::kOmniboxUIElideSuggestionUrlAfterHostDescription,
143 flags_ui::kOsIos,
144 FEATURE_VALUE_TYPE(omnibox::kUIExperimentElideSuggestionUrlAfterHost)},
145 {"omnibox-ui-hide-suggestion-url-scheme",
146 flag_descriptions::kOmniboxUIHideSuggestionUrlSchemeName,
147 flag_descriptions::kOmniboxUIHideSuggestionUrlSchemeDescription,
148 flags_ui::kOsIos,
149 FEATURE_VALUE_TYPE(omnibox::kUIExperimentHideSuggestionUrlScheme)},
150 {"omnibox-ui-hide-suggestion-url-trivial-subdomains",
151 flag_descriptions::kOmniboxUIHideSuggestionUrlTrivialSubdomainsName,
152 flag_descriptions::kOmniboxUIHideSuggestionUrlTrivialSubdomainsDescription,
153 flags_ui::kOsIos,
154 FEATURE_VALUE_TYPE(
Marti Wong87d31d72017-08-25 02:44:52155 omnibox::kUIExperimentHideSuggestionUrlTrivialSubdomains)},
156 {"bookmark-new-generation", flag_descriptions::kBookmarkNewGenerationName,
157 flag_descriptions::kBookmarkNewGenerationDescription, flags_ui::kOsIos,
Marti Wongf0f4dfb2017-09-01 11:24:39158 FEATURE_VALUE_TYPE(kBookmarkNewGeneration)},
Jean-François Geyelin30be5912017-08-25 12:05:38159#if defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0)
160 {"drag_and_drop", flag_descriptions::kDragAndDropName,
161 flag_descriptions::kDragAndDropDescription, flags_ui::kOsIos,
Rohit Rao6a3a481d2017-09-25 19:31:41162 FEATURE_VALUE_TYPE(kDragAndDrop)},
Jean-François Geyelin30be5912017-08-25 12:05:38163#endif
Rohit Rao6a3a481d2017-09-25 19:31:41164 {"tab_switcher_presents_bvc",
165 flag_descriptions::kTabSwitcherPresentsBVCName,
166 flag_descriptions::kTabSwitcherPresentsBVCDescription, flags_ui::kOsIos,
Jean-François Geyelined4cde72017-10-11 11:34:50167 FEATURE_VALUE_TYPE(kTabSwitcherPresentsBVC)},
168 {"safe_area_compatible_toolbar",
169 flag_descriptions::kSafeAreaCompatibleToolbarName,
170 flag_descriptions::kSafeAreaCompatibleToolbarDescription, flags_ui::kOsIos,
Louis Romerod11747a2017-10-20 20:10:35171 FEATURE_VALUE_TYPE(kSafeAreaCompatibleToolbar)},
172 {"external-search", flag_descriptions::kExternalSearchName,
173 flag_descriptions::kExternalSearchDescription, flags_ui::kOsIos,
174 FEATURE_VALUE_TYPE(kExternalSearch)},
sczsa0c91942017-10-26 18:39:59175 {"history-batch-updates-filter",
176 flag_descriptions::kHistoryBatchUpdatesFilterName,
177 flag_descriptions::kHistoryBatchUpdatesFilterDescription, flags_ui::kOsIos,
178 FEATURE_VALUE_TYPE(kHistoryBatchUpdatesFilter)},
Danyao Wang34da6ff2017-10-30 15:16:56179 {"slim-navigation-manager", flag_descriptions::kSlimNavigationManagerName,
180 flag_descriptions::kSlimNavigationManagerDescription, flags_ui::kOsIos,
181 FEATURE_VALUE_TYPE(web::features::kSlimNavigationManager)},
Gregory Chatzinoff6f3a2602017-10-31 06:24:35182 {"ios-share-canonical-url", flag_descriptions::kShareCanonicalURLName,
183 flag_descriptions::kShareCanonicalURLDescription, flags_ui::kOsIos,
184 FEATURE_VALUE_TYPE(activity_services::kShareCanonicalURL)},
sczs9a142dc2017-10-31 23:34:06185 {"property-animations-toolbar",
186 flag_descriptions::kPropertyAnimationsToolbarName,
187 flag_descriptions::kPropertyAnimationsToolbarDescription, flags_ui::kOsIos,
Gauthier Ambardba34b462017-11-06 09:06:42188 FEATURE_VALUE_TYPE(kPropertyAnimationsToolbar)},
Kurt Horimotoa5a922a2017-11-07 00:21:09189 {"new-fullscreen-controller", flag_descriptions::kNewFullscreenName,
190 flag_descriptions::kNewFullscreenDescription, flags_ui::kOsIos,
Gauthier Ambardccc4c682017-11-17 15:36:37191 FEATURE_VALUE_TYPE(fullscreen::features::kNewFullscreen)},
192 {"clean-toolbar", flag_descriptions::kCleanToolbarName,
193 flag_descriptions::kCleanToolbarDescription, flags_ui::kOsIos,
194 FEATURE_VALUE_TYPE(kCleanToolbar)}};
sdefresne14900ee2015-11-27 14:43:21195
196// Add all switches from experimental flags to |command_line|.
197void AppendSwitchesFromExperimentalSettings(base::CommandLine* command_line) {
198 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
199
sdefresne14900ee2015-11-27 14:43:21200 // Web page replay flags.
201 BOOL webPageReplayEnabled = [defaults boolForKey:@"WebPageReplayEnabled"];
202 NSString* webPageReplayProxy =
203 [defaults stringForKey:@"WebPageReplayProxyAddress"];
204 if (webPageReplayEnabled && [webPageReplayProxy length]) {
205 command_line->AppendSwitch(switches::kIOSIgnoreCertificateErrors);
206 // 80 and 443 are the default ports from web page replay.
207 command_line->AppendSwitchASCII(switches::kIOSTestingFixedHttpPort, "80");
208 command_line->AppendSwitchASCII(switches::kIOSTestingFixedHttpsPort, "443");
209 command_line->AppendSwitchASCII(
210 switches::kIOSHostResolverRules,
211 "MAP * " + base::SysNSStringToUTF8(webPageReplayProxy));
212 }
213
sdefresne14900ee2015-11-27 14:43:21214 // Set the UA flag if UseMobileSafariUA is enabled.
215 if ([defaults boolForKey:@"UseMobileSafariUA"]) {
216 // Safari uses "Vesion/", followed by the OS version excluding bugfix, where
217 // Chrome puts its product token.
avi571943672015-12-22 02:12:49218 int32_t major = 0;
219 int32_t minor = 0;
220 int32_t bugfix = 0;
sdefresne14900ee2015-11-27 14:43:21221 base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
222 std::string product = base::StringPrintf("Version/%d.%d", major, minor);
223
224 command_line->AppendSwitchASCII(switches::kUserAgent,
225 web::BuildUserAgentFromProduct(product));
226 }
227
jkrcal7d79de52017-05-05 18:13:10228 // Populate command line flag for fetching missing favicons for NTP tiles.
229 NSString* enableMostLikelyFaviconsFromServer =
230 [defaults stringForKey:@"EnableNtpMostLikelyFaviconsFromServer"];
231 if ([enableMostLikelyFaviconsFromServer isEqualToString:@"Enabled"]) {
232 command_line->AppendSwitch(
233 ntp_tiles::switches::kEnableNtpMostLikelyFaviconsFromServer);
234 } else if ([enableMostLikelyFaviconsFromServer isEqualToString:@"Disabled"]) {
235 command_line->AppendSwitch(
236 ntp_tiles::switches::kDisableNtpMostLikelyFaviconsFromServer);
237 }
238
sdefresne14900ee2015-11-27 14:43:21239 // Freeform commandline flags. These are added last, so that any flags added
240 // earlier in this function take precedence.
241 if ([defaults boolForKey:@"EnableFreeformCommandLineFlags"]) {
242 base::CommandLine::StringVector flags;
243 // Append an empty "program" argument.
244 flags.push_back("");
245
246 // The number of flags corresponds to the number of text fields in
247 // Experimental.plist.
248 const int kNumFreeformFlags = 5;
249 for (int i = 1; i <= kNumFreeformFlags; ++i) {
250 NSString* key =
251 [NSString stringWithFormat:@"FreeformCommandLineFlag%d", i];
252 NSString* flag = [defaults stringForKey:key];
253 if ([flag length]) {
254 flags.push_back(base::SysNSStringToUTF8(flag));
255 }
256 }
257
258 base::CommandLine temp_command_line(flags);
259 command_line->AppendArguments(temp_command_line, false);
260 }
msardafc76f662017-02-24 12:46:28261
justincohendacc85d2017-06-28 23:34:10262 // Populate command line flag for 3rd party keyboard omnibox workaround.
263 NSString* enableThirdPartyKeyboardWorkaround =
264 [defaults stringForKey:@"EnableThirdPartyKeyboardWorkaround"];
265 if ([enableThirdPartyKeyboardWorkaround isEqualToString:@"Enabled"]) {
266 command_line->AppendSwitch(switches::kEnableThirdPartyKeyboardWorkaround);
267 } else if ([enableThirdPartyKeyboardWorkaround isEqualToString:@"Disabled"]) {
268 command_line->AppendSwitch(switches::kDisableThirdPartyKeyboardWorkaround);
269 }
270
msardafc76f662017-02-24 12:46:28271 ios::GetChromeBrowserProvider()->AppendSwitchesFromExperimentalSettings(
272 defaults, command_line);
sdefresne14900ee2015-11-27 14:43:21273}
274
275bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
276 return false;
277}
278
279class FlagsStateSingleton {
280 public:
281 FlagsStateSingleton()
282 : flags_state_(kFeatureEntries, arraysize(kFeatureEntries)) {}
283 ~FlagsStateSingleton() {}
284
285 static FlagsStateSingleton* GetInstance() {
286 return base::Singleton<FlagsStateSingleton>::get();
287 }
288
289 static flags_ui::FlagsState* GetFlagsState() {
290 return &GetInstance()->flags_state_;
291 }
292
293 private:
294 flags_ui::FlagsState flags_state_;
295
296 DISALLOW_COPY_AND_ASSIGN(FlagsStateSingleton);
297};
298} // namespace
299
300void ConvertFlagsToSwitches(flags_ui::FlagsStorage* flags_storage,
301 base::CommandLine* command_line) {
302 FlagsStateSingleton::GetFlagsState()->ConvertFlagsToSwitches(
sdefresnec9763902015-12-02 10:30:11303 flags_storage, command_line, flags_ui::kAddSentinels,
304 switches::kEnableIOSFeatures, switches::kDisableIOSFeatures);
sdefresne14900ee2015-11-27 14:43:21305 AppendSwitchesFromExperimentalSettings(command_line);
306}
307
jkrcalbf073372016-07-29 07:21:31308std::vector<std::string> RegisterAllFeatureVariationParameters(
309 flags_ui::FlagsStorage* flags_storage,
310 base::FeatureList* feature_list) {
311 return FlagsStateSingleton::GetFlagsState()
312 ->RegisterAllFeatureVariationParameters(flags_storage, feature_list);
313}
314
sdefresne14900ee2015-11-27 14:43:21315void GetFlagFeatureEntries(flags_ui::FlagsStorage* flags_storage,
316 flags_ui::FlagAccess access,
317 base::ListValue* supported_entries,
318 base::ListValue* unsupported_entries) {
319 FlagsStateSingleton::GetFlagsState()->GetFlagFeatureEntries(
320 flags_storage, access, supported_entries, unsupported_entries,
321 base::Bind(&SkipConditionalFeatureEntry));
322}
323
324void SetFeatureEntryEnabled(flags_ui::FlagsStorage* flags_storage,
325 const std::string& internal_name,
326 bool enable) {
327 FlagsStateSingleton::GetFlagsState()->SetFeatureEntryEnabled(
328 flags_storage, internal_name, enable);
329}
330
331void ResetAllFlags(flags_ui::FlagsStorage* flags_storage) {
332 FlagsStateSingleton::GetFlagsState()->ResetAllFlags(flags_storage);
333}
334
335namespace testing {
336
337const flags_ui::FeatureEntry* GetFeatureEntries(size_t* count) {
338 *count = arraysize(kFeatureEntries);
339 return kFeatureEntries;
340}
341
342} // namespace testing