blob: 747de62f330103ea9f4296fb79daa70179783b31 [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"
sdefresne14900ee2015-11-27 14:43:2124#include "components/flags_ui/feature_entry.h"
25#include "components/flags_ui/feature_entry_macros.h"
26#include "components/flags_ui/flags_storage.h"
27#include "components/flags_ui/flags_ui_switches.h"
noyau4cfb1332016-10-25 17:05:4228#include "components/ntp_tiles/switches.h"
olivierrobin0c6cd0ca2016-11-24 22:40:3529#include "components/reading_list/core/reading_list_switches.h"
sdefresne36579782016-02-05 11:08:2530#include "components/strings/grit/components_strings.h"
maxbogue455a57e32016-08-14 00:08:3231#include "components/sync/driver/sync_driver_switches.h"
sdefresne14900ee2015-11-27 14:43:2132#include "google_apis/gaia/gaia_switches.h"
sdefresne14900ee2015-11-27 14:43:2133#include "ios/chrome/browser/chrome_switches.h"
sdefresnee7fd94062016-12-12 13:21:0834#include "ios/chrome/browser/google_api_keys.h"
sdefresne14900ee2015-11-27 14:43:2135#include "ios/chrome/grit/ios_strings.h"
36#include "ios/web/public/user_agent.h"
37#include "ios/web/public/web_view_creation_util.h"
38
39#if !defined(OFFICIAL_BUILD)
40#include "components/variations/variations_switches.h"
stkhapuginc1be1792016-12-13 14:30:5341
42#if !defined(__has_feature) || !__has_feature(objc_arc)
43#error "This file requires ARC support."
44#endif
sdefresne14900ee2015-11-27 14:43:2145#endif
46
47namespace {
sdefresne14900ee2015-11-27 14:43:2148// To add a new entry, add to the end of kFeatureEntries. There are two
49// distinct types of entries:
50// . SINGLE_VALUE: entry is either on or off. Use the SINGLE_VALUE_TYPE
51// macro for this type supplying the command line to the macro.
52// . MULTI_VALUE: a list of choices, the first of which should correspond to a
53// deactivated state for this lab (i.e. no command line option). To specify
54// this type of entry use the macro MULTI_VALUE_TYPE supplying it the
55// array of choices.
56// See the documentation of FeatureEntry for details on the fields.
57//
58// When adding a new choice, add it to the end of the list.
59const flags_ui::FeatureEntry kFeatureEntries[] = {
60 {"contextual-search", IDS_IOS_FLAGS_CONTEXTUAL_SEARCH,
mattreynolds1a4181f2016-10-05 23:50:0061 IDS_IOS_FLAGS_CONTEXTUAL_SEARCH_DESCRIPTION, flags_ui::kOsIos,
sdefresne14900ee2015-11-27 14:43:2162 ENABLE_DISABLE_VALUE_TYPE(switches::kEnableContextualSearch,
63 switches::kDisableContextualSearch)},
mattreynolds1a4181f2016-10-05 23:50:0064 {"ios-physical-web", IDS_IOS_FLAGS_PHYSICAL_WEB,
65 IDS_IOS_FLAGS_PHYSICAL_WEB_DESCRIPTION, flags_ui::kOsIos,
66 ENABLE_DISABLE_VALUE_TYPE(switches::kEnableIOSPhysicalWeb,
67 switches::kDisableIOSPhysicalWeb)},
robliao59eed1a2016-10-28 17:12:1668 {"browser-task-scheduler", IDS_IOS_FLAGS_BROWSER_TASK_SCHEDULER_NAME,
69 IDS_IOS_FLAGS_BROWSER_TASK_SCHEDULER_DESCRIPTION, flags_ui::kOsIos,
70 ENABLE_DISABLE_VALUE_TYPE(switches::kEnableBrowserTaskScheduler,
71 switches::kDisableBrowserTaskScheduler)},
sdefresne14900ee2015-11-27 14:43:2172};
73
74// Add all switches from experimental flags to |command_line|.
75void AppendSwitchesFromExperimentalSettings(base::CommandLine* command_line) {
76 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
77
78 // GAIA staging environment.
79 NSString* kGAIAEnvironment = @"GAIAEnvironment";
80 NSString* gaia_environment = [defaults stringForKey:kGAIAEnvironment];
81 if ([gaia_environment isEqualToString:@"Staging"]) {
82 command_line->AppendSwitchASCII(switches::kGoogleApisUrl,
sdefresnee7fd94062016-12-12 13:21:0883 BUILDFLAG(GOOGLE_STAGING_API_URL));
84 command_line->AppendSwitchASCII(switches::kLsoUrl,
85 BUILDFLAG(GOOGLE_STAGING_LSO_URL));
sdefresne14900ee2015-11-27 14:43:2186 } else if ([gaia_environment isEqualToString:@"Test"]) {
sdefresnee7fd94062016-12-12 13:21:0887 command_line->AppendSwitchASCII(switches::kGaiaUrl,
88 BUILDFLAG(GOOGLE_TEST_OAUTH_URL));
sdefresne14900ee2015-11-27 14:43:2189 command_line->AppendSwitchASCII(switches::kGoogleApisUrl,
sdefresnee7fd94062016-12-12 13:21:0890 BUILDFLAG(GOOGLE_TEST_API_URL));
91 command_line->AppendSwitchASCII(switches::kLsoUrl,
92 BUILDFLAG(GOOGLE_TEST_LSO_URL));
sdefresne14900ee2015-11-27 14:43:2193 command_line->AppendSwitchASCII(switches::kSyncServiceURL,
sdefresnee7fd94062016-12-12 13:21:0894 BUILDFLAG(GOOGLE_TEST_SYNC_URL));
sdefresne14900ee2015-11-27 14:43:2195 command_line->AppendSwitchASCII(switches::kOAuth2ClientID,
sdefresnee7fd94062016-12-12 13:21:0896 BUILDFLAG(GOOGLE_TEST_OAUTH_CLIENT_ID));
sdefresne14900ee2015-11-27 14:43:2197 command_line->AppendSwitchASCII(switches::kOAuth2ClientSecret,
sdefresnee7fd94062016-12-12 13:21:0898 BUILDFLAG(GOOGLE_TEST_OAUTH_CLIENT_SECRET));
sdefresne14900ee2015-11-27 14:43:2199 }
100
liaoyukedf4f7e42017-01-07 00:21:10101 // Populate command line flag for the tab strip auto scroll new tabs
102 // experiment from the configuration plist.
103 if ([defaults boolForKey:@"TabStripAutoScrollNewTabsDisabled"])
104 command_line->AppendSwitch(switches::kDisableTabStripAutoScrollNewTabs);
105
sdefresne14900ee2015-11-27 14:43:21106 // Populate command line flag for the Tab Switcher experiment from the
107 // configuration plist.
108 NSString* enableTabSwitcher = [defaults stringForKey:@"EnableTabSwitcher"];
109 if ([enableTabSwitcher isEqualToString:@"Enabled"]) {
110 command_line->AppendSwitch(switches::kEnableTabSwitcher);
111 } else if ([enableTabSwitcher isEqualToString:@"Disabled"]) {
112 command_line->AppendSwitch(switches::kDisableTabSwitcher);
113 }
114
115 // Populate command line flag for the SnapshotLRUCache experiment from the
116 // configuration plist.
117 NSString* enableLRUSnapshotCache =
118 [defaults stringForKey:@"SnapshotLRUCache"];
119 if ([enableLRUSnapshotCache isEqualToString:@"Enabled"]) {
120 command_line->AppendSwitch(switches::kEnableLRUSnapshotCache);
121 } else if ([enableLRUSnapshotCache isEqualToString:@"Disabled"]) {
122 command_line->AppendSwitch(switches::kDisableLRUSnapshotCache);
123 }
124
noyauc7892c12016-05-12 12:22:01125 // Populate command line flag for the AllBookmarks from the
126 // configuration plist.
127 NSString* enableAllBookmarks = [defaults stringForKey:@"AllBookmarks"];
128 if ([enableAllBookmarks isEqualToString:@"Enabled"]) {
129 command_line->AppendSwitch(switches::kEnableAllBookmarksView);
130 } else if ([enableAllBookmarks isEqualToString:@"Disabled"]) {
131 command_line->AppendSwitch(switches::kDisableAllBookmarksView);
132 }
133
sdefresne14900ee2015-11-27 14:43:21134 // Populate command line flags from PasswordGenerationEnabled.
135 NSString* enablePasswordGenerationValue =
136 [defaults stringForKey:@"PasswordGenerationEnabled"];
137 if ([enablePasswordGenerationValue isEqualToString:@"Enabled"]) {
138 command_line->AppendSwitch(switches::kEnableIOSPasswordGeneration);
139 } else if ([enablePasswordGenerationValue isEqualToString:@"Disabled"]) {
140 command_line->AppendSwitch(switches::kDisableIOSPasswordGeneration);
141 }
142
mattreynoldsc9f1df52016-06-29 08:30:04143 // Populate command line flags from PhysicalWebEnabled.
144 NSString* enablePhysicalWebValue =
145 [defaults stringForKey:@"PhysicalWebEnabled"];
146 if ([enablePhysicalWebValue isEqualToString:@"Enabled"]) {
147 command_line->AppendSwitch(switches::kEnableIOSPhysicalWeb);
148 } else if ([enablePhysicalWebValue isEqualToString:@"Disabled"]) {
149 command_line->AppendSwitch(switches::kDisableIOSPhysicalWeb);
150 }
151
sdefresne14900ee2015-11-27 14:43:21152 // Web page replay flags.
153 BOOL webPageReplayEnabled = [defaults boolForKey:@"WebPageReplayEnabled"];
154 NSString* webPageReplayProxy =
155 [defaults stringForKey:@"WebPageReplayProxyAddress"];
156 if (webPageReplayEnabled && [webPageReplayProxy length]) {
157 command_line->AppendSwitch(switches::kIOSIgnoreCertificateErrors);
158 // 80 and 443 are the default ports from web page replay.
159 command_line->AppendSwitchASCII(switches::kIOSTestingFixedHttpPort, "80");
160 command_line->AppendSwitchASCII(switches::kIOSTestingFixedHttpsPort, "443");
161 command_line->AppendSwitchASCII(
162 switches::kIOSHostResolverRules,
163 "MAP * " + base::SysNSStringToUTF8(webPageReplayProxy));
164 }
165
166 if ([defaults boolForKey:@"EnableCredentialManagement"])
167 command_line->AppendSwitch(switches::kEnableCredentialManagerAPI);
168
sdefresne14900ee2015-11-27 14:43:21169 NSString* autoReloadEnabledValue =
170 [defaults stringForKey:@"AutoReloadEnabled"];
171 if ([autoReloadEnabledValue isEqualToString:@"Enabled"]) {
172 command_line->AppendSwitch(switches::kEnableOfflineAutoReload);
173 } else if ([autoReloadEnabledValue isEqualToString:@"Disabled"]) {
174 command_line->AppendSwitch(switches::kDisableOfflineAutoReload);
175 }
176
177 // Populate command line flags from EnableFastWebScrollViewInsets.
178 NSString* enableFastWebScrollViewInsets =
179 [defaults stringForKey:@"EnableFastWebScrollViewInsets"];
180 if ([enableFastWebScrollViewInsets isEqualToString:@"Enabled"]) {
181 command_line->AppendSwitch(switches::kEnableIOSFastWebScrollViewInsets);
182 } else if ([enableFastWebScrollViewInsets isEqualToString:@"Disabled"]) {
183 command_line->AppendSwitch(switches::kDisableIOSFastWebScrollViewInsets);
184 }
185
186 // Populate command line flags from ReaderModeEnabled.
187 if ([defaults boolForKey:@"ReaderModeEnabled"]) {
188 command_line->AppendSwitch(switches::kEnableReaderModeToolbarIcon);
189
190 // Populate command line from ReaderMode Heuristics detection.
191 NSString* readerModeDetectionHeuristics =
192 [defaults stringForKey:@"ReaderModeDetectionHeuristics"];
193 if (!readerModeDetectionHeuristics) {
noyaudb4a2d62016-09-26 11:04:45194 command_line->AppendSwitchASCII(
195 switches::kReaderModeHeuristics,
196 switches::reader_mode_heuristics::kOGArticle);
sdefresne14900ee2015-11-27 14:43:21197 } else if ([readerModeDetectionHeuristics isEqualToString:@"AdaBoost"]) {
noyaudb4a2d62016-09-26 11:04:45198 command_line->AppendSwitchASCII(
199 switches::kReaderModeHeuristics,
200 switches::reader_mode_heuristics::kAdaBoost);
sdefresne14900ee2015-11-27 14:43:21201 } else {
202 DCHECK([readerModeDetectionHeuristics isEqualToString:@"Off"]);
noyaudb4a2d62016-09-26 11:04:45203 command_line->AppendSwitchASCII(switches::kReaderModeHeuristics,
204 switches::reader_mode_heuristics::kNone);
sdefresne14900ee2015-11-27 14:43:21205 }
206 }
207
noyaue0884e42016-11-08 15:26:41208 // Populate command line flags from EnablePopularSites.
209 NSString* EnablePopularSites = [defaults stringForKey:@"EnablePopularSites"];
210 if ([EnablePopularSites isEqualToString:@"Enabled"]) {
noyau4cfb1332016-10-25 17:05:42211 command_line->AppendSwitch(ntp_tiles::switches::kEnableNTPPopularSites);
noyaue0884e42016-11-08 15:26:41212 } else if ([EnablePopularSites isEqualToString:@"Disabled"]) {
213 command_line->AppendSwitch(ntp_tiles::switches::kDisableNTPPopularSites);
noyau4cfb1332016-10-25 17:05:42214 }
215
sdefresne14900ee2015-11-27 14:43:21216 // Set the UA flag if UseMobileSafariUA is enabled.
217 if ([defaults boolForKey:@"UseMobileSafariUA"]) {
218 // Safari uses "Vesion/", followed by the OS version excluding bugfix, where
219 // Chrome puts its product token.
avi571943672015-12-22 02:12:49220 int32_t major = 0;
221 int32_t minor = 0;
222 int32_t bugfix = 0;
sdefresne14900ee2015-11-27 14:43:21223 base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
224 std::string product = base::StringPrintf("Version/%d.%d", major, minor);
225
226 command_line->AppendSwitchASCII(switches::kUserAgent,
227 web::BuildUserAgentFromProduct(product));
228 }
229
sklencarova39c8887a2016-07-19 14:45:57230 // Populate command line flags from QRScanner.
jif3df1b40d2016-09-20 18:56:36231 if ([defaults boolForKey:@"DisableQRCodeReader"]) {
sklencarovac8a562c52016-09-12 10:20:34232 command_line->AppendSwitch(switches::kDisableQRScanner);
jif3df1b40d2016-09-20 18:56:36233 } else {
234 command_line->AppendSwitch(switches::kEnableQRScanner);
sklencarova39c8887a2016-07-19 14:45:57235 }
236
jdonnelly1ca9fd8b2016-08-11 02:29:12237 // Populate command line flag for the Payment Request API.
238 NSString* enable_payment_request =
239 [defaults stringForKey:@"EnablePaymentRequest"];
240 if ([enable_payment_request isEqualToString:@"Enabled"]) {
241 command_line->AppendSwitch(switches::kEnablePaymentRequest);
242 } else if ([enable_payment_request isEqualToString:@"Disabled"]) {
243 command_line->AppendSwitch(switches::kDisablePaymentRequest);
244 }
245
sklencarova6eaf8fc2016-09-13 10:02:34246 // Populate command line flag for Spotlight Actions.
jife9171ba2016-09-20 19:00:03247 if ([defaults boolForKey:@"DisableSpotlightActions"]) {
sklencarova6eaf8fc2016-09-13 10:02:34248 command_line->AppendSwitch(switches::kDisableSpotlightActions);
249 }
250
gambard91ee34f2016-11-30 17:33:03251 // Populate command line flag for the Rename "Save Image" to "Download Image"
252 // experiment.
253 NSString* enableDownloadRenaming =
254 [defaults stringForKey:@"EnableDownloadRenaming"];
255 if ([enableDownloadRenaming isEqualToString:@"Enabled"]) {
256 command_line->AppendSwitch(switches::kEnableDownloadImageRenaming);
257 } else if ([enableDownloadRenaming isEqualToString:@"Disabled"]) {
258 command_line->AppendSwitch(switches::kDisableDownloadImageRenaming);
259 }
260
gambardd2e44fb2017-01-25 09:14:21261 // Populate command line flag for Suggestions UI display.
262 NSString* enableSuggestions = [defaults stringForKey:@"EnableSuggestions"];
263 if ([enableSuggestions isEqualToString:@"Enabled"]) {
264 command_line->AppendSwitch(switches::kEnableSuggestionsUI);
265 } else if ([enableSuggestions isEqualToString:@"Disabled"]) {
266 command_line->AppendSwitch(switches::kDisableSuggestionsUI);
267 }
268
sdefresne14900ee2015-11-27 14:43:21269 // Freeform commandline flags. These are added last, so that any flags added
270 // earlier in this function take precedence.
271 if ([defaults boolForKey:@"EnableFreeformCommandLineFlags"]) {
272 base::CommandLine::StringVector flags;
273 // Append an empty "program" argument.
274 flags.push_back("");
275
276 // The number of flags corresponds to the number of text fields in
277 // Experimental.plist.
278 const int kNumFreeformFlags = 5;
279 for (int i = 1; i <= kNumFreeformFlags; ++i) {
280 NSString* key =
281 [NSString stringWithFormat:@"FreeformCommandLineFlag%d", i];
282 NSString* flag = [defaults stringForKey:key];
283 if ([flag length]) {
284 flags.push_back(base::SysNSStringToUTF8(flag));
285 }
286 }
287
288 base::CommandLine temp_command_line(flags);
289 command_line->AppendArguments(temp_command_line, false);
290 }
291}
292
293bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
294 return false;
295}
296
297class FlagsStateSingleton {
298 public:
299 FlagsStateSingleton()
300 : flags_state_(kFeatureEntries, arraysize(kFeatureEntries)) {}
301 ~FlagsStateSingleton() {}
302
303 static FlagsStateSingleton* GetInstance() {
304 return base::Singleton<FlagsStateSingleton>::get();
305 }
306
307 static flags_ui::FlagsState* GetFlagsState() {
308 return &GetInstance()->flags_state_;
309 }
310
311 private:
312 flags_ui::FlagsState flags_state_;
313
314 DISALLOW_COPY_AND_ASSIGN(FlagsStateSingleton);
315};
316} // namespace
317
318void ConvertFlagsToSwitches(flags_ui::FlagsStorage* flags_storage,
319 base::CommandLine* command_line) {
320 FlagsStateSingleton::GetFlagsState()->ConvertFlagsToSwitches(
sdefresnec9763902015-12-02 10:30:11321 flags_storage, command_line, flags_ui::kAddSentinels,
322 switches::kEnableIOSFeatures, switches::kDisableIOSFeatures);
sdefresne14900ee2015-11-27 14:43:21323 AppendSwitchesFromExperimentalSettings(command_line);
324}
325
jkrcalbf073372016-07-29 07:21:31326std::vector<std::string> RegisterAllFeatureVariationParameters(
327 flags_ui::FlagsStorage* flags_storage,
328 base::FeatureList* feature_list) {
329 return FlagsStateSingleton::GetFlagsState()
330 ->RegisterAllFeatureVariationParameters(flags_storage, feature_list);
331}
332
sdefresne14900ee2015-11-27 14:43:21333void GetFlagFeatureEntries(flags_ui::FlagsStorage* flags_storage,
334 flags_ui::FlagAccess access,
335 base::ListValue* supported_entries,
336 base::ListValue* unsupported_entries) {
337 FlagsStateSingleton::GetFlagsState()->GetFlagFeatureEntries(
338 flags_storage, access, supported_entries, unsupported_entries,
339 base::Bind(&SkipConditionalFeatureEntry));
340}
341
342void SetFeatureEntryEnabled(flags_ui::FlagsStorage* flags_storage,
343 const std::string& internal_name,
344 bool enable) {
345 FlagsStateSingleton::GetFlagsState()->SetFeatureEntryEnabled(
346 flags_storage, internal_name, enable);
347}
348
349void ResetAllFlags(flags_ui::FlagsStorage* flags_storage) {
350 FlagsStateSingleton::GetFlagsState()->ResetAllFlags(flags_storage);
351}
352
353namespace testing {
354
355const flags_ui::FeatureEntry* GetFeatureEntries(size_t* count) {
356 *count = arraysize(kFeatureEntries);
357 return kFeatureEntries;
358}
359
360} // namespace testing