Create experimental flag to force App Store Rating Promo.

This change creates an experimental flag to override the Promos Manager
and App Store Rating trigger criteria to force the App Store Rating
promo to display when the app is launched or resumed.

In a later CL, the flag will be updated to support forcing
the Post Restore SignIn promos.

Bug: 1359065
Change-Id: I914a4ab8dedc47417f1ac2d9bbb6b669938090d3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3939945
Reviewed-by: Rohit Rao <rohitrao@chromium.org>
Reviewed-by: Benjamin Williams <bwwilliams@google.com>
Commit-Queue: Hira Mahmood <hiramahmood@google.com>
Cr-Commit-Position: refs/heads/main@{#1058332}
diff --git a/ios/chrome/browser/flags/system_flags.h b/ios/chrome/browser/flags/system_flags.h
index fefd3ff..4e2abc4 100644
--- a/ios/chrome/browser/flags/system_flags.h
+++ b/ios/chrome/browser/flags/system_flags.h
@@ -72,6 +72,11 @@
 // Whether the DCheckIsFatal feature should be disabled.
 bool AreDCHECKCrashesDisabled();
 
+// Returns the name of the promo to be forced to display when the app is
+// launched or resumed. Returns empty string if no promo is to be forced
+// to display. Always returns nil for users in stable/beta.
+NSString* GetForcedPromoToDisplay();
+
 }  // namespace experimental_flags
 
 #endif  // IOS_CHROME_BROWSER_FLAGS_SYSTEM_FLAGS_H_
diff --git a/ios/chrome/browser/flags/system_flags.mm b/ios/chrome/browser/flags/system_flags.mm
index 12172cd..95b0ed5 100644
--- a/ios/chrome/browser/flags/system_flags.mm
+++ b/ios/chrome/browser/flags/system_flags.mm
@@ -34,6 +34,7 @@
 NSString* const kOriginServerHost = @"AlternateOriginServerHost";
 NSString* const kWhatsNewPromoStatus = @"WhatsNewPromoStatus";
 NSString* const kClearApplicationGroup = @"ClearApplicationGroup";
+NSString* const kNextPromoForDisplayOverride = @"NextPromoForDisplayOverride";
 BASE_FEATURE(kEnableThirdPartyKeyboardWorkaround,
              "EnableThirdPartyKeyboardWorkaround",
              base::FEATURE_ENABLED_BY_DEFAULT);
@@ -125,4 +126,9 @@
   return base::FeatureList::IsEnabled(kEnableThirdPartyKeyboardWorkaround);
 }
 
+NSString* GetForcedPromoToDisplay() {
+  return [[NSUserDefaults standardUserDefaults]
+      stringForKey:kNextPromoForDisplayOverride];
+}
+
 }  // namespace experimental_flags
diff --git a/ios/chrome/browser/promos_manager/constants.cc b/ios/chrome/browser/promos_manager/constants.cc
index 7d3392ae..a3671a60 100644
--- a/ios/chrome/browser/promos_manager/constants.cc
+++ b/ios/chrome/browser/promos_manager/constants.cc
@@ -12,8 +12,6 @@
 const std::string kImpressionPromoKey = "promo";
 const std::string kImpressionDayKey = "day";
 const int kNumDaysImpressionHistoryStored = 365;
-
-// Prefix used when stringifying promos.
 const std::string kPromoStringifyPrefix = "promos_manager::Promo::";
 
 // WARNING - PLEASE READ: Sadly, we cannot switch over strings in C++, so be
diff --git a/ios/chrome/browser/promos_manager/constants.h b/ios/chrome/browser/promos_manager/constants.h
index b31456e..1e1f4d8 100644
--- a/ios/chrome/browser/promos_manager/constants.h
+++ b/ios/chrome/browser/promos_manager/constants.h
@@ -17,6 +17,9 @@
 // Dictionary key for `day` in stored impression (base::Value).
 extern const std::string kImpressionDayKey;
 
+// Prefix used when stringifying promos.
+extern const std::string kPromoStringifyPrefix;
+
 // The max number of days for impression history to be stored & maintained.
 extern const int kNumDaysImpressionHistoryStored;
 
diff --git a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
index ac54acf..490aded 100644
--- a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
+++ b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
@@ -136,6 +136,26 @@
 		</dict>
 		<dict>
 			<key>Type</key>
+			<string>PSMultiValueSpecifier</string>
+			<key>Title</key>
+			<string>Force Promo</string>
+			<key>Key</key>
+			<string>NextPromoForDisplayOverride</string>
+			<key>DefaultValue</key>
+			<string></string>
+			<key>Values</key>
+			<array>
+				<string></string>
+				<string>promos_manager::Promo::AppStoreRating</string>
+			</array>
+			<key>Titles</key>
+			<array>
+				<string>Disabled (No Promos Forced)</string>
+				<string>App Store Rating</string>
+			</array>
+		</dict>
+		<dict>
+			<key>Type</key>
 			<string>PSGroupSpecifier</string>
 			<key>Title</key>
 			<string>Debug Settings</string>
diff --git a/ios/chrome/browser/ui/promos_manager/BUILD.gn b/ios/chrome/browser/ui/promos_manager/BUILD.gn
index 61c1efa..96b8960 100644
--- a/ios/chrome/browser/ui/promos_manager/BUILD.gn
+++ b/ios/chrome/browser/ui/promos_manager/BUILD.gn
@@ -61,6 +61,7 @@
     "//ios/chrome/app/strings",
     "//ios/chrome/browser",
     "//ios/chrome/browser/application_context",
+    "//ios/chrome/browser/flags:system_flags",
     "//ios/chrome/browser/main:public",
     "//ios/chrome/browser/promos_manager:constants",
     "//ios/chrome/browser/ui/app_store_rating",
diff --git a/ios/chrome/browser/ui/promos_manager/promos_manager_mediator.mm b/ios/chrome/browser/ui/promos_manager/promos_manager_mediator.mm
index 3be27a11..2961de6 100644
--- a/ios/chrome/browser/ui/promos_manager/promos_manager_mediator.mm
+++ b/ios/chrome/browser/ui/promos_manager/promos_manager_mediator.mm
@@ -8,6 +8,8 @@
 #import <map>
 
 #import "base/containers/small_map.h"
+#import "base/strings/sys_string_conversions.h"
+#import "ios/chrome/browser/flags/system_flags.h"
 #import "ios/chrome/browser/promos_manager/constants.h"
 #import "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -39,8 +41,21 @@
 
 - (absl::optional<promos_manager::Promo>)nextPromoForDisplay {
   DCHECK_NE(_promosManager, nullptr);
-
+  NSString* forcedPromoName = [self forcedPromoToDisplay];
+  if ([forcedPromoName length] > 0) {
+    absl::optional<promos_manager::Promo> forcedPromo =
+        promos_manager::PromoForName(base::SysNSStringToUTF8(forcedPromoName));
+    DCHECK(forcedPromo);
+    return forcedPromo;
+  }
   return self.promosManager->NextPromoForDisplay();
 }
 
+// Returns the promo selected in the Force Promo experimental setting.
+// If none are selected, returns empty string. If user is in beta/stable,
+// this method always returns nil.
+- (NSString*)forcedPromoToDisplay {
+  return experimental_flags::GetForcedPromoToDisplay();
+}
+
 @end