[iOS][DefaultBrowserPromo] Migrate non-modal promo to the FET
This CL:
- Migrates the default browser non-modal promo to the FET.
- Check FET to determine if promo should/would be shown if migration
flag is enabled.
- Records events to both the FET and UserDefaults in case of reverse
migration.
Bug: 383772478
Change-Id: I4604fb89a59ae7fb68d59d45d1dcc58f94047b00
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6179700
Reviewed-by: Sylvain Defresne <sdefresne@chromium.org>
Commit-Queue: Cheick Cisse <cheickcisse@google.com>
Reviewed-by: Robbie Gibson <rkgibson@google.com>
Reviewed-by: Guillaume Jenkins <gujen@google.com>
Cr-Commit-Position: refs/heads/main@{#1415051}
NOKEYCHECK=True
GitOrigin-RevId: 05785c0b22108c965d578d643c1bcfaa8ea99279
diff --git a/chrome/browser/default_browser/model/BUILD.gn b/chrome/browser/default_browser/model/BUILD.gn
index 2df6c93..57f7d71 100644
--- a/chrome/browser/default_browser/model/BUILD.gn
+++ b/chrome/browser/default_browser/model/BUILD.gn
@@ -85,6 +85,7 @@
"default_browser_promo_event_exporter.mm",
]
deps = [
+ ":features",
":utils",
"//components/feature_engagement/public",
]
diff --git a/chrome/browser/default_browser/model/default_browser_promo_event_exporter.mm b/chrome/browser/default_browser/model/default_browser_promo_event_exporter.mm
index 81e3fb0..5930fd0 100644
--- a/chrome/browser/default_browser/model/default_browser_promo_event_exporter.mm
+++ b/chrome/browser/default_browser/model/default_browser_promo_event_exporter.mm
@@ -4,8 +4,13 @@
#import "ios/chrome/browser/default_browser/model/default_browser_promo_event_exporter.h"
+#import <UIKit/UIKit.h>
+
+#import "base/apple/foundation_util.h"
#import "base/time/time.h"
#import "components/feature_engagement/public/event_constants.h"
+#import "ios/chrome/browser/default_browser/model/features.h"
+#import "ios/chrome/browser/default_browser/model/utils.h"
namespace {
@@ -24,12 +29,16 @@
std::vector<EventData> events_to_migrate;
// Migrate the FRE promo event.
+ // TODO(crbug.com/382733018): Clean up the default browser promos eligibility
+ // tracking migration code.
if (!FRETimestampMigrationDone()) {
AddFREPromoEvent(events_to_migrate);
LogFRETimestampMigrationDone();
}
// Migrate promo interest signals
+ // TODO(crbug.com/382733018): Clean up the default browser promos eligibility
+ // tracking migration code.
if (!IsPromoInterestEventMigrationDone()) {
AddPromoInterestEvents(
events_to_migrate, DefaultPromoTypeGeneral,
@@ -46,12 +55,30 @@
LogPromoInterestEventMigrationDone();
}
+ // TODO(crbug.com/382733018): Clean up the default browser promos eligibility
+ // tracking migration code.
if (!IsPromoImpressionsMigrationDone()) {
AddGenericPromoImpressions(events_to_migrate);
AddTailoredPromoImpressions(events_to_migrate);
LogPromoImpressionsMigrationDone();
}
+ // Migrate the default browser's non-modal promo events.
+ // TODO(crbug.com/391166425): Clean up the non-modal promo migration code.
+ if (IsNonModalPromoMigrationEnabled() && !IsNonModalPromoMigrationDone()) {
+ NSDate* last_interaction = LastTimeUserInteractedWithNonModalPromo();
+ if (last_interaction && UserInteractionWithNonModalPromoCount() > 0) {
+ const NSInteger count = UserInteractionWithNonModalPromoCount();
+ for (NSInteger i = 0; i < count; ++i) {
+ events_to_migrate.emplace_back(
+ feature_engagement::events::
+ kNonModalDefaultBrowserPromoUrlPasteTrigger,
+ DaysSinceTime(base::Time::FromNSDate(last_interaction)));
+ }
+ }
+ LogNonModalPromoMigrationDone();
+ }
+
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), std::move(events_to_migrate)));
diff --git a/chrome/browser/default_browser/model/default_browser_promo_event_exporter_unittest.mm b/chrome/browser/default_browser/model/default_browser_promo_event_exporter_unittest.mm
index aa99259..9754857 100644
--- a/chrome/browser/default_browser/model/default_browser_promo_event_exporter_unittest.mm
+++ b/chrome/browser/default_browser/model/default_browser_promo_event_exporter_unittest.mm
@@ -60,7 +60,7 @@
int GetExportEventsCount() { return export_events_.size(); }
- // Initializes the feature engagement tracker with the default browser
+ // Initializes the feature engagement tracker with the default browser
// exporter and set basic common conditions for default browser promos.
void InitTrackerAndSetBasicConditions() {
// Initialize tracker with the default browser exporter.
@@ -354,3 +354,84 @@
EXPECT_FALSE(tracker_->WouldTriggerHelpUI(
feature_engagement::kIPHiOSPromoAllTabsFeature));
}
+
+// Checks that the event exporter migrates the events.
+TEST_F(DefaultBrowserEventExporterTest, TestNonModalPromoEventsMigration) {
+ // No events to export.
+ RequestExportEventsAndVerifyCallback();
+ EXPECT_EQ(GetExportEventsCount(), 0);
+
+ ClearDefaultBrowserPromoData();
+
+ // Check when there is only 1 event.
+ LogUserInteractionWithNonModalPromo(0);
+ RequestExportEventsAndVerifyCallback();
+ EXPECT_EQ(GetExportEventsCount(), 1);
+ // Check that exporting second time will not have any events.
+ RequestExportEventsAndVerifyCallback();
+ EXPECT_EQ(GetExportEventsCount(), 0);
+
+ // Check when there is only 2 event.
+ ClearDefaultBrowserPromoData();
+ LogUserInteractionWithNonModalPromo(2);
+ RequestExportEventsAndVerifyCallback();
+ EXPECT_EQ(GetExportEventsCount(), 3);
+ // Check that exporting second time will not have any events.
+ RequestExportEventsAndVerifyCallback();
+ EXPECT_EQ(GetExportEventsCount(), 0);
+}
+
+// Checks that none of the promos trigger when there are no events exported.
+TEST_F(DefaultBrowserEventExporterTest, TestNonModalMigrationNoEvents) {
+ LogUserInteractionWithNonModalPromo(1);
+
+ // Initialize tracker.
+ InitTrackerAndSetBasicConditions();
+
+ // None of the promos should trigger.
+ EXPECT_FALSE(tracker_->WouldTriggerHelpUI(
+ feature_engagement::kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature));
+}
+
+// Checks that after migration, the promo can be triggered if the last
+// interaction isn't in cooldown and the interaction count is less than 10.
+TEST_F(DefaultBrowserEventExporterTest, TestNonModalMigrationConditionsMet) {
+ SimulateUserInteractionWithNonModalPromo(kMoreThan30Days,
+ /*interaction_count=*/1);
+
+ // Initialize tracker.
+ InitTrackerAndSetBasicConditions();
+
+ EXPECT_TRUE(tracker_->WouldTriggerHelpUI(
+ feature_engagement::kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature));
+}
+
+// Checks that after migration, the promo cannot be triggered if the last
+// interaction is in cooldown and the interaction count is less than 10.
+TEST_F(DefaultBrowserEventExporterTest,
+ TestNonModalMigrationCooldownConditionsNotMet) {
+ // Write to user defaults before creating the tracker.
+ SimulateUserInteractionWithNonModalPromo(kMoreThan3Day,
+ /*interaction_count=*/1);
+
+ // Initialize tracker.
+ InitTrackerAndSetBasicConditions();
+
+ EXPECT_FALSE(tracker_->WouldTriggerHelpUI(
+ feature_engagement::kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature));
+}
+
+// Checks that after migration, the promo cannot be triggered if the last
+// interaction is not in cooldown but the interaction count is more than 10.
+TEST_F(DefaultBrowserEventExporterTest,
+ TestNonModalMigrationInteractionConditionNotMet) {
+ // Write to user defaults before creating the tracker.
+ SimulateUserInteractionWithNonModalPromo(kMoreThan3Day,
+ /*interaction_count=*/10);
+
+ // Initialize tracker.
+ InitTrackerAndSetBasicConditions();
+
+ EXPECT_FALSE(tracker_->WouldTriggerHelpUI(
+ feature_engagement::kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature));
+}
diff --git a/chrome/browser/default_browser/model/utils.h b/chrome/browser/default_browser/model/utils.h
index 1edb71b..5b0b5af 100644
--- a/chrome/browser/default_browser/model/utils.h
+++ b/chrome/browser/default_browser/model/utils.h
@@ -68,6 +68,10 @@
// interacted with a non-modal promo.
extern NSString* const kLastTimeUserInteractedWithNonModalPromo;
+// Key in storage containing an int indicating the number of times the
+// user has interacted with a non-modal promo.
+extern NSString* const kUserInteractedWithNonModalPromoCount;
+
// Key in storage containing an NSDate indicating the last time a user
// interacted with ANY full screen promo. The string value is kept from when the
// promos first launched to avoid changing the behavior for users that have
@@ -352,7 +356,7 @@
// Log to UserDefaults FRE timestamp migration is done.
void LogFRETimestampMigrationDone();
-// Returns whether FRE timestamp migratin is done.
+// Returns whether FRE timestamp migrating is done.
BOOL FRETimestampMigrationDone();
// Log to UserDefaults promo interest event migration is done.
@@ -371,6 +375,15 @@
// presented.
void RecordDefaultBrowserPromoLastAction(IOSDefaultBrowserPromoAction action);
+// Log to UserDefaults non-modal promo migration done.
+void LogNonModalPromoMigrationDone();
+
+// Returns whether the non-modal promo migration is done.
+bool IsNonModalPromoMigrationDone();
+
+// Gets the date when the user last interacted with the non-modal promo.
+NSDate* LastTimeUserInteractedWithNonModalPromo();
+
// Returns the last action, if any, that the user took when a Default Browser
// Promo was presented.
std::optional<IOSDefaultBrowserPromoAction> DefaultBrowserPromoLastAction();
diff --git a/chrome/browser/default_browser/model/utils.mm b/chrome/browser/default_browser/model/utils.mm
index 560b7ea..86b9d6c 100644
--- a/chrome/browser/default_browser/model/utils.mm
+++ b/chrome/browser/default_browser/model/utils.mm
@@ -44,11 +44,6 @@
NSString* const kLastSignificantUserEventAllTabs =
@"lastSignificantUserEventAllTabs";
-// Key in storage containing an int indicating the number of times the
-// user has interacted with a non-modal promo.
-NSString* const kUserInteractedWithNonModalPromoCount =
- @"userInteractedWithNonModalPromoCount";
-
// Action string for "Appear" event of the promo.
const char kAppearAction[] = "Appear";
@@ -360,6 +355,8 @@
NSString* const kLastHTTPURLOpenTime = @"lastHTTPURLOpenTime";
NSString* const kLastTimeUserInteractedWithNonModalPromo =
@"lastTimeUserInteractedWithNonModalPromo";
+NSString* const kUserInteractedWithNonModalPromoCount =
+ @"userInteractedWithNonModalPromoCount";
NSString* const kLastTimeUserInteractedWithFullscreenPromo =
@"lastTimeUserInteractedWithFullscreenPromo";
NSString* const kAllTimestampsAppLaunchColdStart =
@@ -396,6 +393,7 @@
@"promo_impressions_migration_done";
NSString* const kTimestampTriggerCriteriaExperimentStarted =
@"TimestampTriggerCriteriaExperimentStarted";
+NSString* const kNonModalPromoMigrationDone = @"kNonModalPromoMigrationDone";
std::vector<base::Time> LoadTimestampsForPromoType(DefaultPromoType type) {
return LoadActiveTimestampsForKey(StorageKeyForDefaultPromoType(type),
@@ -996,6 +994,18 @@
return number.boolValue;
}
+void LogNonModalPromoMigrationDone() {
+ NSDictionary<NSString*, NSObject*>* update =
+ @{kNonModalPromoMigrationDone : @YES};
+ UpdateStorageWithDictionary(update);
+}
+
+bool IsNonModalPromoMigrationDone() {
+ NSNumber* number =
+ GetObjectFromStorageForKey<NSNumber>(kNonModalPromoMigrationDone);
+ return number.boolValue;
+}
+
void RecordDefaultBrowserPromoLastAction(IOSDefaultBrowserPromoAction action) {
GetApplicationContext()->GetLocalState()->SetInteger(
prefs::kIosDefaultBrowserPromoLastAction, static_cast<int>(action));
@@ -1011,3 +1021,8 @@
int last_action_int = last_action->GetValue()->GetInt();
return static_cast<IOSDefaultBrowserPromoAction>(last_action_int);
}
+
+NSDate* LastTimeUserInteractedWithNonModalPromo() {
+ return GetObjectFromStorageForKey<NSDate>(
+ kLastTimeUserInteractedWithNonModalPromo);
+}
diff --git a/chrome/browser/default_browser/model/utils_test_support.h b/chrome/browser/default_browser/model/utils_test_support.h
index 4a5d547..8b38865 100644
--- a/chrome/browser/default_browser/model/utils_test_support.h
+++ b/chrome/browser/default_browser/model/utils_test_support.h
@@ -33,4 +33,8 @@
DefaultPromoType type,
const base::TimeDelta& timeAgo);
+// Overwrite local storage for non-modal promo interaction.
+void SimulateUserInteractionWithNonModalPromo(base::TimeDelta time_ago,
+ int interaction_count);
+
#endif // IOS_CHROME_BROWSER_DEFAULT_BROWSER_MODEL_UTILS_TEST_SUPPORT_H_
diff --git a/chrome/browser/default_browser/model/utils_test_support.mm b/chrome/browser/default_browser/model/utils_test_support.mm
index d7f325c..7bdd853 100644
--- a/chrome/browser/default_browser/model/utils_test_support.mm
+++ b/chrome/browser/default_browser/model/utils_test_support.mm
@@ -57,3 +57,14 @@
StoreTimestampsForPromoType(type, std::move(times));
}
+
+void SimulateUserInteractionWithNonModalPromo(base::TimeDelta time_ago,
+ int interaction_count) {
+ NSDictionary<NSString*, NSObject*>* values = @{
+ kLastTimeUserInteractedWithNonModalPromo : (base::Time::Now() - time_ago)
+ .ToNSDate(),
+ kUserInteractedWithNonModalPromoCount :
+ [NSNumber numberWithInt:interaction_count]
+ };
+ SetValuesInStorage(values);
+}
diff --git a/chrome/browser/default_promo/ui_bundled/BUILD.gn b/chrome/browser/default_promo/ui_bundled/BUILD.gn
index 61058b4..4396d71 100644
--- a/chrome/browser/default_promo/ui_bundled/BUILD.gn
+++ b/chrome/browser/default_promo/ui_bundled/BUILD.gn
@@ -50,7 +50,9 @@
":coordinator",
"//base",
"//components/feature_engagement/public",
+ "//components/feature_engagement/public:feature_constants",
"//ios/chrome/app/strings",
+ "//ios/chrome/browser/default_browser/model:features",
"//ios/chrome/browser/default_browser/model:utils",
"//ios/chrome/browser/feature_engagement/model",
"//ios/chrome/browser/infobars/ui_bundled/banners",
@@ -114,6 +116,7 @@
"//ios/chrome/browser/signin/model:fake_system_identity",
"//ios/chrome/test:eg_test_support+eg2",
"//ios/chrome/test/earl_grey:eg_test_support+eg2",
+ "//ios/chrome/test/earl_grey:switches",
"//ios/testing/earl_grey:eg_test_support+eg2",
"//net:test_support",
"//ui/base",
diff --git a/chrome/browser/default_promo/ui_bundled/DEPS b/chrome/browser/default_promo/ui_bundled/DEPS
index 92390be..145a9b6 100644
--- a/chrome/browser/default_promo/ui_bundled/DEPS
+++ b/chrome/browser/default_promo/ui_bundled/DEPS
@@ -1,8 +1,7 @@
include_rules = [
- "+ios/chrome/browser/default_browser/model/promo_statistics.h",
- "+ios/chrome/browser/default_browser/model/utils.h",
"+ios/chrome/browser/feature_engagement/model/tracker_factory.h",
"+ios/chrome/browser/promos_manager/model",
"+ios/chrome/browser/infobars/ui_bundled",
"+ios/chrome/browser/promos_manager/ui_bundled",
+ "+ios/chrome/browser/default_browser/model",
]
diff --git a/chrome/browser/default_promo/ui_bundled/default_browser_promo_non_modal_coordinator.mm b/chrome/browser/default_promo/ui_bundled/default_browser_promo_non_modal_coordinator.mm
index e495216..6f4b18d 100644
--- a/chrome/browser/default_promo/ui_bundled/default_browser_promo_non_modal_coordinator.mm
+++ b/chrome/browser/default_promo/ui_bundled/default_browser_promo_non_modal_coordinator.mm
@@ -5,7 +5,9 @@
#import "ios/chrome/browser/default_promo/ui_bundled/default_browser_promo_non_modal_coordinator.h"
#import "base/notreached.h"
+#import "components/feature_engagement/public/feature_constants.h"
#import "components/feature_engagement/public/tracker.h"
+#import "ios/chrome/browser/default_browser/model/features.h"
#import "ios/chrome/browser/default_browser/model/utils.h"
#import "ios/chrome/browser/default_promo/ui_bundled/default_browser_promo_non_modal_commands.h"
#import "ios/chrome/browser/feature_engagement/model/tracker_factory.h"
@@ -125,6 +127,15 @@
- (void)infobarWasDismissed {
self.bannerViewController = nil;
+
+ if (IsNonModalPromoMigrationEnabled()) {
+ feature_engagement::Tracker* tracker =
+ feature_engagement::TrackerFactory::GetForProfile(
+ self.browser->GetProfile());
+ tracker->Dismissed(
+ feature_engagement::kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature);
+ }
+
id<DefaultBrowserPromoNonModalCommands> handler =
HandlerForProtocol(self.browser->GetCommandDispatcher(),
DefaultBrowserPromoNonModalCommands);
diff --git a/chrome/browser/default_promo/ui_bundled/default_browser_promo_non_modal_egtest.mm b/chrome/browser/default_promo/ui_bundled/default_browser_promo_non_modal_egtest.mm
index 4d055b6..897aa26 100644
--- a/chrome/browser/default_promo/ui_bundled/default_browser_promo_non_modal_egtest.mm
+++ b/chrome/browser/default_promo/ui_bundled/default_browser_promo_non_modal_egtest.mm
@@ -5,6 +5,7 @@
#import "base/functional/bind.h"
#import "base/ios/ios_util.h"
#import "base/test/ios/wait_util.h"
+#import "components/feature_engagement/public/feature_constants.h"
#import "components/strings/grit/components_strings.h"
#import "ios/chrome/browser/infobars/ui_bundled/banners/infobar_banner_constants.h"
#import "ios/chrome/browser/shared/public/features/features.h"
@@ -13,6 +14,7 @@
#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
#import "ios/chrome/test/earl_grey/chrome_test_case.h"
+#import "ios/chrome/test/earl_grey/test_switches.h"
#import "ios/testing/earl_grey/app_launch_manager.h"
#import "ios/testing/earl_grey/earl_grey_test.h"
#import "net/test/embedded_test_server/embedded_test_server.h"
@@ -46,6 +48,14 @@
- (void)setUp {
[super setUp];
+
+ AppLaunchConfiguration config;
+ config.relaunch_policy = ForceRelaunchByCleanShutdown;
+ config.additional_args.push_back(
+ std::string("-") + test_switches::kEnableIPH +
+ "=IPH_iOSPromoNonModalUrlPasteDefaultBrowser");
+ [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config];
+
GREYAssertTrue(self.testServer->Start(), @"Server did not start.");
[ChromeEarlGrey clearDefaultBrowserPromoData];
}
diff --git a/chrome/browser/shared/coordinator/DEPS b/chrome/browser/shared/coordinator/DEPS
index ef3a265..71316ff 100644
--- a/chrome/browser/shared/coordinator/DEPS
+++ b/chrome/browser/shared/coordinator/DEPS
@@ -2,6 +2,7 @@
# TODO(crbug.com/40259387): Remove this include once the folders have been
# moved.
"+ios/chrome/browser/ui",
+ "+ios/chrome/browser/feature_engagement/model/tracker_factory.h",
# Use ios/chrome/browser/authentication/ui_bundled/signin_earl_grey.h instead
"-ios/chrome/browser/authentication/ui_bundled/signin_earl_grey_app_interface.h",
diff --git a/chrome/browser/shared/coordinator/default_browser_promo/BUILD.gn b/chrome/browser/shared/coordinator/default_browser_promo/BUILD.gn
index 2f96ff0..e7dd7b1 100644
--- a/chrome/browser/shared/coordinator/default_browser_promo/BUILD.gn
+++ b/chrome/browser/shared/coordinator/default_browser_promo/BUILD.gn
@@ -9,13 +9,18 @@
]
deps = [
"//base",
+ "//components/feature_engagement/public",
+ "//components/feature_engagement/public:feature_constants",
+ "//ios/chrome/browser/default_browser/model:features",
"//ios/chrome/browser/default_browser/model:utils",
"//ios/chrome/browser/default_promo/ui_bundled:coordinator",
+ "//ios/chrome/browser/feature_engagement/model",
"//ios/chrome/browser/overlays/model",
"//ios/chrome/browser/shared/coordinator/scene:observing_scene_agent",
"//ios/chrome/browser/shared/coordinator/scene:scene_state_header",
"//ios/chrome/browser/shared/coordinator/scene:scene_state_observer",
"//ios/chrome/browser/shared/model/browser",
+ "//ios/chrome/browser/shared/model/profile",
"//ios/chrome/browser/shared/model/web_state_list",
"//ios/chrome/browser/shared/public/commands",
"//ios/chrome/browser/shared/public/features",
@@ -31,12 +36,17 @@
":default_browser_promo",
"//base",
"//base/test:test_support",
+ "//components/feature_engagement/public",
+ "//components/feature_engagement/public:feature_constants",
+ "//components/feature_engagement/test:test_support",
"//ios/chrome/app:app_internal",
"//ios/chrome/app/application_delegate:app_state",
"//ios/chrome/app/application_delegate:test_support",
+ "//ios/chrome/browser/default_browser/model:event_exporter",
"//ios/chrome/browser/default_browser/model:test_support",
"//ios/chrome/browser/default_browser/model:utils",
"//ios/chrome/browser/default_promo/ui_bundled:coordinator",
+ "//ios/chrome/browser/feature_engagement/model",
"//ios/chrome/browser/infobars/model",
"//ios/chrome/browser/infobars/model/test",
"//ios/chrome/browser/overlays/model",
diff --git a/chrome/browser/shared/coordinator/default_browser_promo/non_modal_default_browser_promo_scheduler_scene_agent.mm b/chrome/browser/shared/coordinator/default_browser_promo/non_modal_default_browser_promo_scheduler_scene_agent.mm
index 51874d6..3289b3d 100644
--- a/chrome/browser/shared/coordinator/default_browser_promo/non_modal_default_browser_promo_scheduler_scene_agent.mm
+++ b/chrome/browser/shared/coordinator/default_browser_promo/non_modal_default_browser_promo_scheduler_scene_agent.mm
@@ -6,15 +6,21 @@
#import "base/notreached.h"
#import "base/timer/timer.h"
+#import "components/feature_engagement/public/event_constants.h"
+#import "components/feature_engagement/public/feature_constants.h"
+#import "components/feature_engagement/public/tracker.h"
+#import "ios/chrome/browser/default_browser/model/features.h"
#import "ios/chrome/browser/default_browser/model/utils.h"
#import "ios/chrome/browser/default_promo/ui_bundled/default_browser_promo_non_modal_commands.h"
#import "ios/chrome/browser/default_promo/ui_bundled/default_browser_promo_non_modal_metrics_util.h"
+#import "ios/chrome/browser/feature_engagement/model/tracker_factory.h"
#import "ios/chrome/browser/overlays/model/public/overlay_presenter.h"
#import "ios/chrome/browser/overlays/model/public/overlay_presenter_observer_bridge.h"
#import "ios/chrome/browser/shared/coordinator/scene/scene_state.h"
#import "ios/chrome/browser/shared/model/browser/browser_observer_bridge.h"
#import "ios/chrome/browser/shared/model/browser/browser_provider.h"
#import "ios/chrome/browser/shared/model/browser/browser_provider_interface.h"
+#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
#import "ios/chrome/browser/shared/model/web_state_list/active_web_state_observation_forwarder.h"
#import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
#import "ios/chrome/browser/shared/model/web_state_list/web_state_list_observer_bridge.h"
@@ -105,6 +111,9 @@
// The trigger reason for the in-progress promo flow.
@property(nonatomic, assign) PromoReason currentPromoReason;
+// The tracker for feature engagement.
+@property(nonatomic, readonly) feature_engagement::Tracker* tracker;
+
// The browser that this scheduler uses to listen to events, such as page loads
// and overlay events
@property(nonatomic, assign) Browser* browser;
@@ -215,6 +224,11 @@
return false;
}
+ if (IsNonModalPromoMigrationEnabled()) {
+ return self.tracker->WouldTriggerHelpUI(
+ feature_engagement::kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature);
+ }
+
if (UserInNonModalPromoCooldown()) {
return false;
}
@@ -230,6 +244,11 @@
_userInteractionWithNonModalPromoCount =
UserInteractionWithNonModalPromoCount();
+ if (!IsNonModalPromoMigrationEnabled() && IsNonModalPromoMigrationDone()) {
+ self.tracker->NotifyEvent(feature_engagement::events::
+ kNonModalDefaultBrowserPromoUrlPasteTrigger);
+ }
+
[_handler showDefaultBrowserNonModalPromo];
}
@@ -242,7 +261,7 @@
if (currentPromoReason != PromoReasonNone && !promoIsShowing) {
LogNonModalPromoAction(NonModalPromoAction::kBackgroundCancel,
MetricTypeForPromoReason(currentPromoReason),
- _userInteractionWithNonModalPromoCount);
+ [self nonModalPromoInteractionCount]);
}
[self cancelShowPromoTimer];
[self dismissPromoAnimated:NO];
@@ -251,7 +270,7 @@
- (void)logPromoAppear:(PromoReason)currentPromoReason {
LogNonModalPromoAction(NonModalPromoAction::kAppear,
MetricTypeForPromoReason(currentPromoReason),
- _userInteractionWithNonModalPromoCount);
+ [self nonModalPromoInteractionCount]);
}
- (void)logPromoAction:(PromoReason)currentPromoReason
@@ -260,7 +279,7 @@
IOSDefaultBrowserPromoAction::kActionButton);
LogNonModalPromoAction(NonModalPromoAction::kAccepted,
MetricTypeForPromoReason(currentPromoReason),
- _userInteractionWithNonModalPromoCount);
+ [self nonModalPromoInteractionCount]);
LogNonModalTimeOnScreen(promoShownTime);
LogUserInteractionWithNonModalPromo(_userInteractionWithNonModalPromoCount);
@@ -275,7 +294,7 @@
RecordDefaultBrowserPromoLastAction(IOSDefaultBrowserPromoAction::kDismiss);
LogNonModalPromoAction(NonModalPromoAction::kDismiss,
MetricTypeForPromoReason(currentPromoReason),
- _userInteractionWithNonModalPromoCount);
+ [self nonModalPromoInteractionCount]);
LogNonModalTimeOnScreen(promoShownTime);
LogUserInteractionWithNonModalPromo(_userInteractionWithNonModalPromoCount);
}
@@ -284,7 +303,7 @@
promoShownTime:(base::TimeTicks)promoShownTime {
LogNonModalPromoAction(NonModalPromoAction::kTimeout,
MetricTypeForPromoReason(currentPromoReason),
- _userInteractionWithNonModalPromoCount);
+ [self nonModalPromoInteractionCount]);
LogNonModalTimeOnScreen(promoShownTime);
LogUserInteractionWithNonModalPromo(_userInteractionWithNonModalPromoCount);
}
@@ -335,6 +354,12 @@
}
}
+- (feature_engagement::Tracker*)tracker {
+ CHECK(_browser);
+ return feature_engagement::TrackerFactory::GetForProfile(
+ _browser->GetProfile());
+}
+
#pragma mark - WebStateListObserving
- (void)didChangeWebStateList:(WebStateList*)webStateList
@@ -489,6 +514,14 @@
if (![self promoCanBeDisplayed] || self.promoIsShowing) {
return;
}
+
+ if (IsNonModalPromoMigrationEnabled() &&
+ !self.tracker->ShouldTriggerHelpUI(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)) {
+ return;
+ }
+
_showPromoTimer = nullptr;
[self notifyHandlerShowPromo];
self.promoIsShowing = YES;
@@ -522,4 +555,24 @@
}
}
+- (int)nonModalPromoInteractionCount {
+ if (!IsNonModalPromoMigrationEnabled()) {
+ return _userInteractionWithNonModalPromoCount;
+ }
+
+ unsigned int interactions = 0;
+ std::vector<std::pair<feature_engagement::EventConfig, int>> events =
+ self.tracker->ListEvents(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature);
+ for (const auto& event : events) {
+ if (event.first.name == feature_engagement::events::
+ kNonModalDefaultBrowserPromoUrlPasteTrigger) {
+ interactions = event.second;
+ break;
+ }
+ }
+ return interactions;
+}
+
@end
diff --git a/chrome/browser/shared/coordinator/default_browser_promo/non_modal_default_browser_promo_scheduler_scene_agent_unittest.mm b/chrome/browser/shared/coordinator/default_browser_promo/non_modal_default_browser_promo_scheduler_scene_agent_unittest.mm
index 29a4486..07943cb 100644
--- a/chrome/browser/shared/coordinator/default_browser_promo/non_modal_default_browser_promo_scheduler_scene_agent_unittest.mm
+++ b/chrome/browser/shared/coordinator/default_browser_promo/non_modal_default_browser_promo_scheduler_scene_agent_unittest.mm
@@ -10,12 +10,18 @@
#import "base/test/scoped_feature_list.h"
#import "base/test/task_environment.h"
#import "base/time/time.h"
+#import "components/feature_engagement/public/event_constants.h"
+#import "components/feature_engagement/public/feature_constants.h"
+#import "components/feature_engagement/test/mock_tracker.h"
+#import "components/feature_engagement/test/test_tracker.h"
#import "ios/chrome/app/application_delegate/app_state.h"
#import "ios/chrome/app/application_delegate/fake_startup_information.h"
+#import "ios/chrome/browser/default_browser/model/default_browser_promo_event_exporter.h"
#import "ios/chrome/browser/default_browser/model/utils.h"
#import "ios/chrome/browser/default_browser/model/utils_test_support.h"
#import "ios/chrome/browser/default_promo/ui_bundled/default_browser_promo_non_modal_commands.h"
#import "ios/chrome/browser/default_promo/ui_bundled/default_browser_promo_non_modal_metrics_util.h"
+#import "ios/chrome/browser/feature_engagement/model/tracker_factory.h"
#import "ios/chrome/browser/infobars/model/infobar_ios.h"
#import "ios/chrome/browser/infobars/model/infobar_manager_impl.h"
#import "ios/chrome/browser/infobars/model/test/fake_infobar_ios.h"
@@ -45,20 +51,31 @@
namespace {
+std::unique_ptr<KeyedService> BuildFeatureEngagementMockTracker(
+ web::BrowserState* context) {
+ return std::make_unique<feature_engagement::test::MockTracker>();
+}
+
class NonModalDefaultBrowserPromoSchedulerSceneAgentTest : public PlatformTest {
protected:
NonModalDefaultBrowserPromoSchedulerSceneAgentTest() {}
void SetUp() override {
TestProfileIOS::Builder builder;
- std::unique_ptr<TestProfileIOS> profile = std::move(builder).Build();
+ builder.AddTestingFactory(
+ feature_engagement::TrackerFactory::GetInstance(),
+ base::BindRepeating(&BuildFeatureEngagementMockTracker));
+ profile_ = std::move(builder).Build();
+
+ mock_tracker_ = static_cast<feature_engagement::test::MockTracker*>(
+ feature_engagement::TrackerFactory::GetForProfile(profile_.get()));
FakeStartupInformation* startup_information =
[[FakeStartupInformation alloc] init];
app_state_ =
[[AppState alloc] initWithStartupInformation:startup_information];
scene_state_ = [[FakeSceneState alloc] initWithAppState:app_state_
- profile:profile.get()];
+ profile:profile_.get()];
scene_state_.scene = static_cast<UIWindowScene*>(
[[[UIApplication sharedApplication] connectedScenes] anyObject]);
@@ -107,16 +124,23 @@
->SetPresentationContext(nullptr);
}
+ base::RepeatingCallback<void(bool)> BoolArgumentQuitClosure() {
+ return base::IgnoreArgs<bool>(run_loop_.QuitClosure());
+ }
+
base::test::TaskEnvironment task_env_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
base::test::ScopedFeatureList feature_list_;
IOSChromeScopedTestingLocalState scoped_testing_local_state_;
+ std::unique_ptr<TestProfileIOS> profile_;
raw_ptr<web::FakeWebState> test_web_state_;
raw_ptr<Browser> browser_;
+ raw_ptr<feature_engagement::test::MockTracker> mock_tracker_;
FakeOverlayPresentationContext overlay_presentation_context_;
id promo_commands_handler_;
NonModalDefaultBrowserPromoSchedulerSceneAgent* scheduler_;
id application_ = nil;
+ base::RunLoop run_loop_;
AppState* app_state_;
FakeSceneState* scene_state_;
};
@@ -124,6 +148,18 @@
// Tests that the omnibox paste event triggers the promo to show.
TEST_F(NonModalDefaultBrowserPromoSchedulerSceneAgentTest,
TestOmniboxPasteShowsPromo) {
+ // Mock the FET tracker.
+ EXPECT_CALL(*mock_tracker_,
+ WouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*mock_tracker_,
+ ShouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+
[scheduler_ logUserPastedInOmnibox];
// Finish loading the page.
@@ -147,6 +183,18 @@
// promo.
TEST_F(NonModalDefaultBrowserPromoSchedulerSceneAgentTest,
TestFirstPartySchemeShowsPromo) {
+ // Mock the FET tracker.
+ EXPECT_CALL(*mock_tracker_,
+ WouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*mock_tracker_,
+ ShouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+
[scheduler_ logUserEnteredAppViaFirstPartyScheme];
// Finish loading the page.
@@ -169,6 +217,18 @@
// Tests that the completed share event triggers the promo.
TEST_F(NonModalDefaultBrowserPromoSchedulerSceneAgentTest,
TestShareCompletedShowsPromo) {
+ // Mock the FET tracker.
+ EXPECT_CALL(*mock_tracker_,
+ WouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*mock_tracker_,
+ ShouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+
[scheduler_ logUserFinishedActivityFlow];
// Finish loading the page.
@@ -187,6 +247,18 @@
// the event is stored.
TEST_F(NonModalDefaultBrowserPromoSchedulerSceneAgentTest,
TestTimeoutDismissesPromo) {
+ // Mock the FET tracker.
+ EXPECT_CALL(*mock_tracker_,
+ WouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*mock_tracker_,
+ ShouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+
[scheduler_ logUserPastedInOmnibox];
// Finish loading the page.
@@ -214,6 +286,18 @@
// Tests that if the user takes the promo action, that is handled correctly.
TEST_F(NonModalDefaultBrowserPromoSchedulerSceneAgentTest,
TestActionDismissesPromo) {
+ // Mock the FET tracker.
+ EXPECT_CALL(*mock_tracker_,
+ WouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*mock_tracker_,
+ ShouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+
[scheduler_ logUserPastedInOmnibox];
// Finish loading the page.
@@ -237,12 +321,45 @@
// Check that NSUserDefaults has been updated.
EXPECT_EQ(UserInteractionWithNonModalPromoCount(), 1);
+
+ // Check that the FET has been updated.
+ std::unique_ptr<feature_engagement::Tracker> tracker =
+ feature_engagement::CreateTestTracker(
+ std::make_unique<DefaultBrowserEventExporter>());
+ tracker->AddOnInitializedCallback(BoolArgumentQuitClosure());
+ run_loop_.Run();
+ unsigned int interactions = 0;
+ std::vector<std::pair<feature_engagement::EventConfig, int>> events =
+ tracker->ListEvents(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature);
+ for (const auto& event : events) {
+ if (event.first.name == feature_engagement::events::
+ kNonModalDefaultBrowserPromoUrlPasteTrigger) {
+ interactions = event.second;
+ break;
+ }
+ }
+
+ EXPECT_EQ((int)interactions, 1);
}
// Tests that if the user manages to trigger multiple interactions, the
// interactions count is only incremented once.
TEST_F(NonModalDefaultBrowserPromoSchedulerSceneAgentTest,
TestMultipleInteractionsOnlyIncrementsCountOnce) {
+ // Mock the FET tracker.
+ EXPECT_CALL(*mock_tracker_,
+ WouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*mock_tracker_,
+ ShouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+
[scheduler_ logUserPastedInOmnibox];
// Finish loading the page.
@@ -263,12 +380,44 @@
// Check that NSUserDefaults has been updated, incremented only by 1.
EXPECT_EQ(UserInteractionWithNonModalPromoCount(), 1);
+
+ // Check that the FET has been updated.
+ std::unique_ptr<feature_engagement::Tracker> tracker =
+ feature_engagement::CreateTestTracker(
+ std::make_unique<DefaultBrowserEventExporter>());
+ tracker->AddOnInitializedCallback(BoolArgumentQuitClosure());
+ run_loop_.Run();
+ unsigned int interactions = 0;
+ std::vector<std::pair<feature_engagement::EventConfig, int>> events =
+ tracker->ListEvents(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature);
+ for (const auto& event : events) {
+ if (event.first.name == feature_engagement::events::
+ kNonModalDefaultBrowserPromoUrlPasteTrigger) {
+ interactions = event.second;
+ break;
+ }
+ }
+
+ EXPECT_EQ((int)interactions, 1);
}
// Tests that if the user switches to a different tab before the post-load timer
// finishes, the promo does not show.
TEST_F(NonModalDefaultBrowserPromoSchedulerSceneAgentTest,
TestTabSwitchPreventsPromoShown) {
+ // Mock the FET tracker.
+ EXPECT_CALL(*mock_tracker_,
+ WouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*mock_tracker_,
+ ShouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
[scheduler_ logUserPastedInOmnibox];
// Finish loading the page.
@@ -290,6 +439,17 @@
// Tests that if a message is triggered on page load, the promo is not shown.
TEST_F(NonModalDefaultBrowserPromoSchedulerSceneAgentTest,
TestMessagePreventsPromoShown) {
+ // Mock the FET tracker.
+ EXPECT_CALL(*mock_tracker_,
+ WouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*mock_tracker_,
+ ShouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
[scheduler_ logUserPastedInOmnibox];
// Finish loading the page.
@@ -325,6 +485,18 @@
// does not update the shown promo count.
TEST_F(NonModalDefaultBrowserPromoSchedulerSceneAgentTest,
TestBackgroundingDismissesPromo) {
+ // Mock the FET tracker.
+ EXPECT_CALL(*mock_tracker_,
+ WouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*mock_tracker_,
+ ShouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+
[scheduler_ logUserPastedInOmnibox];
// Finish loading the page.
@@ -347,12 +519,45 @@
// Check that NSUserDefaults has not been updated.
EXPECT_EQ(UserInteractionWithNonModalPromoCount(), 0);
+
+ // Check that the FET has been updated.
+ std::unique_ptr<feature_engagement::Tracker> tracker =
+ feature_engagement::CreateTestTracker(
+ std::make_unique<DefaultBrowserEventExporter>());
+ tracker->AddOnInitializedCallback(BoolArgumentQuitClosure());
+ run_loop_.Run();
+ unsigned int interactions = 0;
+ std::vector<std::pair<feature_engagement::EventConfig, int>> events =
+ tracker->ListEvents(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature);
+ for (const auto& event : events) {
+ if (event.first.name == feature_engagement::events::
+ kNonModalDefaultBrowserPromoUrlPasteTrigger) {
+ interactions = event.second;
+ break;
+ }
+ }
+
+ EXPECT_EQ((int)interactions, 0);
}
// Tests that entering the tab grid with the promo showing hides the promo but
// does not update the shown promo count.
TEST_F(NonModalDefaultBrowserPromoSchedulerSceneAgentTest,
TestTabGridDismissesPromo) {
+ // Mock the FET tracker.
+ EXPECT_CALL(*mock_tracker_,
+ WouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*mock_tracker_,
+ ShouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+
[scheduler_ logUserPastedInOmnibox];
// Finish loading the page.
@@ -374,11 +579,44 @@
// Check that NSUserDefaults has not been updated.
EXPECT_EQ(UserInteractionWithNonModalPromoCount(), 0);
+
+ // Check that the FET has been updated.
+ std::unique_ptr<feature_engagement::Tracker> tracker =
+ feature_engagement::CreateTestTracker(
+ std::make_unique<DefaultBrowserEventExporter>());
+ tracker->AddOnInitializedCallback(BoolArgumentQuitClosure());
+ run_loop_.Run();
+ unsigned int interactions = 0;
+ std::vector<std::pair<feature_engagement::EventConfig, int>> events =
+ tracker->ListEvents(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature);
+ for (const auto& event : events) {
+ if (event.first.name == feature_engagement::events::
+ kNonModalDefaultBrowserPromoUrlPasteTrigger) {
+ interactions = event.second;
+ break;
+ }
+ }
+
+ EXPECT_EQ((int)interactions, 0);
}
// Tests background cancel metric logs correctly.
TEST_F(NonModalDefaultBrowserPromoSchedulerSceneAgentTest,
TestBackgroundCancelMetric) {
+ // Mock the FET tracker.
+ EXPECT_CALL(*mock_tracker_,
+ WouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*mock_tracker_,
+ ShouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+
base::HistogramTester histogram_tester;
histogram_tester.ExpectUniqueSample(
"IOS.DefaultBrowserPromo.NonModal.VisitPastedLink",
@@ -400,6 +638,18 @@
// Tests background cancel metric is not logged after a promo is shown.
TEST_F(NonModalDefaultBrowserPromoSchedulerSceneAgentTest,
TestBackgroundCancelMetricNotLogAfterPromoShown) {
+ // Mock the FET tracker.
+ EXPECT_CALL(*mock_tracker_,
+ WouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*mock_tracker_,
+ ShouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+
base::HistogramTester histogram_tester;
histogram_tester.ExpectUniqueSample(
"IOS.DefaultBrowserPromo.NonModal.VisitPastedLink",
@@ -431,6 +681,18 @@
// Tests background cancel metric is not logged after a promo is dismissed.
TEST_F(NonModalDefaultBrowserPromoSchedulerSceneAgentTest,
TestBackgroundCancelMetricNotLogAfterPromoDismiss) {
+ // Mock the FET tracker.
+ EXPECT_CALL(*mock_tracker_,
+ WouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*mock_tracker_,
+ ShouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+
base::HistogramTester histogram_tester;
histogram_tester.ExpectUniqueSample(
"IOS.DefaultBrowserPromo.NonModal.VisitPastedLink",
@@ -477,6 +739,17 @@
NSUserDefaults* standardDefaults = [NSUserDefaults standardUserDefaults];
[standardDefaults setObject:[NSDate date]
forKey:@"lastTimeUserInteractedWithFullscreenPromo"];
+ // Mock the FET tracker.
+ EXPECT_CALL(*mock_tracker_,
+ WouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(false));
+ EXPECT_CALL(*mock_tracker_,
+ ShouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(false));
[scheduler_ logUserPastedInOmnibox];
@@ -525,6 +798,18 @@
// crbug.com/1224427
TEST_F(NonModalDefaultBrowserPromoSchedulerSceneAgentTest,
NoDCHECKIfPromoNotShown) {
+ // Mock the FET tracker.
+ EXPECT_CALL(*mock_tracker_,
+ WouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*mock_tracker_,
+ ShouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(true));
+
[scheduler_ logUserPastedInOmnibox];
// Switch to a new tab before loading a page. This will prevent the promo from
@@ -556,6 +841,18 @@
LogUserInteractionWithNonModalPromo(i);
}
+ // Mock the FET tracker.
+ EXPECT_CALL(*mock_tracker_,
+ WouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(false));
+ EXPECT_CALL(*mock_tracker_,
+ ShouldTriggerHelpUI(testing::Ref(
+ feature_engagement::
+ kIPHiOSPromoNonModalUrlPasteDefaultBrowserFeature)))
+ .WillRepeatedly(testing::Return(false));
+
base::HistogramTester histogram_tester;
[scheduler_ logUserPastedInOmnibox];