[iOS] Create Reminder Notifications Overflow Menu Badge IPH Feature
This CL introduces a new Feature Engagement Tracker (FET) feature for a new badge displayed on the "Set a Reminder" action in the overflow menu. It tracks user interaction with this action and displays the badge to promote its availability and encourage adoption. Specifically, this CL: - Adds new events and feature constants related to the "Set a Reminder" badge. - Implements the FET configuration for the new badge IPH, including trigger and usage conditions. - Integrates the FET with the overflow menu mediator to display the new badge and track user taps on the "Set a Reminder" action. - Adds unit tests to verify the correct behavior of the new FET feature. - Updates FET metrics actions and histograms. Demo video: https://drive.google.com/file/d/1vVKgm1-EtwdPfYdeZBRe_rsMYxl1raRg/view?usp=sharing&resourcekey=0-LChnR7dZXG4LzITfxuqAUQ Change-Id: If9e4b8a92cb44e71b2f46f86c0f3e89c470dc98b Fixed: Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6233853 Commit-Queue: Benjamin Williams <bwwilliams@google.com> Reviewed-by: Robbie Gibson <rkgibson@google.com> Reviewed-by: Sylvain Defresne <sdefresne@chromium.org> Cr-Commit-Position: refs/heads/main@{#1421448}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
0a84f818cf
commit
b17d7c4a73
components/feature_engagement/public
event_constants.ccevent_constants.hfeature_configurations.ccfeature_constants.ccfeature_constants.hfeature_list.ccfeature_list.h
ios/chrome/browser
feature_engagement
ui
popup_menu
overflow_menu
tools/metrics
@ -148,6 +148,10 @@ const char kLensOverlayEntrypointUsed[] = "lens_overlay_entrypoint_used";
|
||||
const char kIOSTabReminderScheduled[] = "tab_reminder_scheduled";
|
||||
const char kIOSReminderNotificationsOverflowMenuBubbleIPHTrigger[] =
|
||||
"ios_reminder_notifications_overflow_menu_bubble_iph_trigger";
|
||||
const char kIOSOverflowMenuSetTabReminderTapped[] =
|
||||
"ios_overflow_menu_set_tab_reminder_tapped";
|
||||
const char kIOSReminderNotificationsOverflowMenuNewBadgeIPHTrigger[] =
|
||||
"ios_reminder_notifications_overflow_menu_new_badge_iph_trigger";
|
||||
#endif // BUILDFLAG(IS_IOS)
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
|
@ -287,6 +287,11 @@ extern const char kIOSTabReminderScheduled[];
|
||||
// The Reminder Notifications Overflow Menu Bubble IPH was triggered.
|
||||
extern const char kIOSReminderNotificationsOverflowMenuBubbleIPHTrigger[];
|
||||
|
||||
// The user tapped the "Set a Reminder" item in the overflow menu.
|
||||
extern const char kIOSOverflowMenuSetTabReminderTapped[];
|
||||
|
||||
// The Reminder Notifications Overflow Menu New Badge IPH was triggered.
|
||||
extern const char kIOSReminderNotificationsOverflowMenuNewBadgeIPHTrigger[];
|
||||
#endif // BUILDFLAG(IS_IOS)
|
||||
|
||||
// Android.
|
||||
|
@ -2205,6 +2205,35 @@ std::optional<FeatureConfig> GetClientSideFeatureConfig(
|
||||
return config;
|
||||
}
|
||||
|
||||
if (kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature.name ==
|
||||
feature->name) {
|
||||
FeatureConfig config;
|
||||
config.valid = true;
|
||||
// No availability requirement for this feature.
|
||||
config.availability = Comparator(ANY, 0);
|
||||
// No session rate limit for this feature.
|
||||
config.session_rate = Comparator(ANY, 0);
|
||||
// Initially, show to users who haven't tapped the "Set a Reminder" overflow
|
||||
// menu action yet.
|
||||
config.used = EventConfig(
|
||||
feature_engagement::events::kIOSOverflowMenuSetTabReminderTapped,
|
||||
Comparator(EQUAL, 0), feature_engagement::kMaxStoragePeriod,
|
||||
feature_engagement::kMaxStoragePeriod);
|
||||
// The New Badge IPH should not be triggered more than 3 times
|
||||
// in total.
|
||||
config.trigger = EventConfig(
|
||||
feature_engagement::events::
|
||||
kIOSReminderNotificationsOverflowMenuNewBadgeIPHTrigger,
|
||||
Comparator(LESS_THAN, 3), feature_engagement::kMaxStoragePeriod,
|
||||
feature_engagement::kMaxStoragePeriod);
|
||||
// Don't show if the user has already scheduled a tab reminder.
|
||||
config.event_configs.insert(
|
||||
EventConfig(feature_engagement::events::kIOSTabReminderScheduled,
|
||||
Comparator(EQUAL, 0), feature_engagement::kMaxStoragePeriod,
|
||||
feature_engagement::kMaxStoragePeriod));
|
||||
return config;
|
||||
}
|
||||
|
||||
if (kIPHiOSReplaceSyncPromosWithSignInPromos.name == feature->name) {
|
||||
// A config to show a user education bubble from the account row in the
|
||||
// settings page. Will be shown only the first time user signs-in from
|
||||
|
@ -653,6 +653,9 @@ BASE_FEATURE(kIPHiOSDefaultBrowserBannerPromoFeature,
|
||||
BASE_FEATURE(kIPHiOSReminderNotificationsOverflowMenuBubbleFeature,
|
||||
"IPH_iOSReminderNotificationsOverflowMenuBubbleFeature",
|
||||
base::FEATURE_ENABLED_BY_DEFAULT);
|
||||
BASE_FEATURE(kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature,
|
||||
"IPH_iOSReminderNotificationsOverflowMenuNewBadgeFeature",
|
||||
base::FEATURE_ENABLED_BY_DEFAULT);
|
||||
|
||||
// Non-FET feature.
|
||||
BASE_FEATURE(kDefaultBrowserEligibilitySlidingWindow,
|
||||
|
@ -276,6 +276,8 @@ FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHiOSSharedTabGroupForeground);
|
||||
FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHiOSDefaultBrowserBannerPromoFeature);
|
||||
FEATURE_CONSTANTS_DECLARE_FEATURE(
|
||||
kIPHiOSReminderNotificationsOverflowMenuBubbleFeature);
|
||||
FEATURE_CONSTANTS_DECLARE_FEATURE(
|
||||
kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature);
|
||||
|
||||
// A feature flag to enable and parametrize the sliding window of time for a
|
||||
// user's eligibility to be shown a default browser promo. This is not an FET
|
||||
|
@ -163,6 +163,7 @@ const base::Feature* const kAllFeatures[] = {
|
||||
&kIPHiOSSharedTabGroupForeground,
|
||||
&kIPHiOSDefaultBrowserBannerPromoFeature,
|
||||
&kIPHiOSReminderNotificationsOverflowMenuBubbleFeature,
|
||||
&kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature,
|
||||
#endif // BUILDFLAG(IS_IOS)
|
||||
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
|
||||
BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
|
||||
|
@ -288,6 +288,9 @@ DEFINE_VARIATION_PARAM(kIPHiOSDefaultBrowserBannerPromoFeature,
|
||||
"IPH_iOSDefaultBrowserBannerPromoFeature");
|
||||
DEFINE_VARIATION_PARAM(kIPHiOSReminderNotificationsOverflowMenuBubbleFeature,
|
||||
"IPH_iOSReminderNotificationsOverflowMenuBubbleFeature");
|
||||
DEFINE_VARIATION_PARAM(
|
||||
kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature,
|
||||
"IPH_iOSReminderNotificationsOverflowMenuNewBadgeFeature");
|
||||
#endif // BUILDFLAG(IS_IOS)
|
||||
|
||||
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
|
||||
@ -665,6 +668,8 @@ inline constexpr flags_ui::FeatureEntry::FeatureVariation
|
||||
VARIATION_ENTRY(kIPHiOSSharedTabGroupForeground),
|
||||
VARIATION_ENTRY(kIPHiOSDefaultBrowserBannerPromoFeature),
|
||||
VARIATION_ENTRY(kIPHiOSReminderNotificationsOverflowMenuBubbleFeature),
|
||||
VARIATION_ENTRY(
|
||||
kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature),
|
||||
#elif BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
|
||||
BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
|
||||
VARIATION_ENTRY(kIPHBatterySaverModeFeature),
|
||||
|
@ -1051,3 +1051,108 @@ TEST_F(
|
||||
feature_engagement::
|
||||
kIPHiOSReminderNotificationsOverflowMenuBubbleFeature));
|
||||
}
|
||||
|
||||
// Verifies the Reminder Notifications Overflow Menu New Badge IPH should
|
||||
// trigger when preconditions are met.
|
||||
TEST_F(FeatureEngagementTest,
|
||||
TestReminderNotificationsOverflowMenuNewBadgeIPHShouldTrigger) {
|
||||
feature_engagement::test::ScopedIphFeatureList list;
|
||||
list.InitAndEnableFeatures(
|
||||
{feature_engagement::
|
||||
kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature});
|
||||
|
||||
std::unique_ptr<feature_engagement::Tracker> tracker =
|
||||
feature_engagement::CreateTestTracker();
|
||||
// Ensures the tracker is initialized.
|
||||
tracker->AddOnInitializedCallback(BoolArgumentQuitClosure());
|
||||
run_loop_.Run();
|
||||
|
||||
EXPECT_TRUE(tracker->ShouldTriggerHelpUI(
|
||||
feature_engagement::
|
||||
kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature));
|
||||
tracker->Dismissed(
|
||||
feature_engagement::
|
||||
kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature);
|
||||
}
|
||||
|
||||
// Verifies the Reminder Notifications Overflow Menu New Badge IPH should not
|
||||
// trigger after tapping "Set a Reminder" (used event).
|
||||
TEST_F(
|
||||
FeatureEngagementTest,
|
||||
TestReminderNotificationsOverflowMenuNewBadgeIPHShouldNotTriggerAfterTapped) {
|
||||
feature_engagement::test::ScopedIphFeatureList list;
|
||||
list.InitAndEnableFeatures(
|
||||
{feature_engagement::
|
||||
kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature});
|
||||
|
||||
std::unique_ptr<feature_engagement::Tracker> tracker =
|
||||
feature_engagement::CreateTestTracker();
|
||||
// Ensures the tracker is initialized.
|
||||
tracker->AddOnInitializedCallback(BoolArgumentQuitClosure());
|
||||
run_loop_.Run();
|
||||
|
||||
// Simulates tapping "Set a Reminder" (used event).
|
||||
tracker->NotifyEvent(
|
||||
feature_engagement::events::kIOSOverflowMenuSetTabReminderTapped);
|
||||
|
||||
EXPECT_FALSE(tracker->ShouldTriggerHelpUI(
|
||||
feature_engagement::
|
||||
kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature));
|
||||
}
|
||||
|
||||
// Verifies the Reminder Notifications Overflow Menu New Badge IPH should not
|
||||
// trigger if a tab reminder was already scheduled (used event - historical
|
||||
// usage).
|
||||
TEST_F(
|
||||
FeatureEngagementTest,
|
||||
TestReminderNotificationsOverflowMenuNewBadgeIPHShouldNotTriggerAfterReminderScheduled) {
|
||||
feature_engagement::test::ScopedIphFeatureList list;
|
||||
list.InitAndEnableFeatures(
|
||||
{feature_engagement::
|
||||
kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature});
|
||||
|
||||
std::unique_ptr<feature_engagement::Tracker> tracker =
|
||||
feature_engagement::CreateTestTracker();
|
||||
// Ensures the tracker is initialized.
|
||||
tracker->AddOnInitializedCallback(BoolArgumentQuitClosure());
|
||||
run_loop_.Run();
|
||||
|
||||
// Simulates a reminder already scheduled (used event).
|
||||
tracker->NotifyEvent(feature_engagement::events::kIOSTabReminderScheduled);
|
||||
|
||||
EXPECT_FALSE(tracker->ShouldTriggerHelpUI(
|
||||
feature_engagement::
|
||||
kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature));
|
||||
}
|
||||
|
||||
// Verifies the Reminder Notifications Overflow Menu New Badge IPH should not
|
||||
// trigger after reaching the trigger limit (3 times).
|
||||
TEST_F(
|
||||
FeatureEngagementTest,
|
||||
TestReminderNotificationsOverflowMenuNewBadgeIPHShouldNotTriggerAfterLimit) {
|
||||
feature_engagement::test::ScopedIphFeatureList list;
|
||||
list.InitAndEnableFeatures(
|
||||
{feature_engagement::
|
||||
kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature});
|
||||
|
||||
std::unique_ptr<feature_engagement::Tracker> tracker =
|
||||
feature_engagement::CreateTestTracker();
|
||||
// Ensures the tracker is initialized.
|
||||
tracker->AddOnInitializedCallback(BoolArgumentQuitClosure());
|
||||
run_loop_.Run();
|
||||
|
||||
// Trigger IPH 3 times.
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
EXPECT_TRUE(tracker->ShouldTriggerHelpUI(
|
||||
feature_engagement::
|
||||
kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature));
|
||||
tracker->Dismissed(
|
||||
feature_engagement::
|
||||
kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature);
|
||||
}
|
||||
|
||||
// IPH should not trigger again after reaching the limit.
|
||||
EXPECT_FALSE(tracker->ShouldTriggerHelpUI(
|
||||
feature_engagement::
|
||||
kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature));
|
||||
}
|
||||
|
@ -826,20 +826,47 @@ OverflowMenuFooter* CreateOverflowMenuManagedFooter(
|
||||
NSString* hideItemText = l10n_util::GetNSString(
|
||||
IDS_IOS_REMINDER_NOTIFICATIONS_HIDE_SET_A_REMINDER);
|
||||
|
||||
return
|
||||
[self createOverflowMenuActionWithNameID:
|
||||
IDS_IOS_REMINDER_NOTIFICATIONS_SET_A_REMINDER
|
||||
actionType:overflow_menu::ActionType::
|
||||
SetTabReminder
|
||||
symbolName:kBellBadgeSymbol
|
||||
systemSymbol:YES
|
||||
monochromeSymbol:NO
|
||||
accessibilityID:kToolsMenuSetTabReminder
|
||||
hideItemText:hideItemText
|
||||
handler:^{
|
||||
// TODO(crbug.com/389912106): Display
|
||||
// the new 'Set a Reminder' UI.
|
||||
}];
|
||||
__weak __typeof(self) weakSelf = self;
|
||||
|
||||
OverflowMenuAction* action = [self
|
||||
createOverflowMenuActionWithNameID:
|
||||
IDS_IOS_REMINDER_NOTIFICATIONS_SET_A_REMINDER
|
||||
actionType:overflow_menu::ActionType::
|
||||
SetTabReminder
|
||||
symbolName:kBellBadgeSymbol
|
||||
systemSymbol:YES
|
||||
monochromeSymbol:NO
|
||||
accessibilityID:kToolsMenuSetTabReminder
|
||||
hideItemText:hideItemText
|
||||
handler:^{
|
||||
[weakSelf notifySetTabReminderActionTapped];
|
||||
}];
|
||||
|
||||
if (_engagementTracker &&
|
||||
_engagementTracker->ShouldTriggerHelpUI(
|
||||
feature_engagement::
|
||||
kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature)) {
|
||||
action.displayNewLabelIcon = YES;
|
||||
|
||||
_engagementTracker->Dismissed(
|
||||
feature_engagement::
|
||||
kIPHiOSReminderNotificationsOverflowMenuNewBadgeFeature);
|
||||
}
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
// Notifies the FET that the user tapped the "Set a Reminder" action.
|
||||
- (void)notifySetTabReminderActionTapped {
|
||||
CHECK(
|
||||
send_tab_to_self::IsSendTabIOSPushNotificationsEnabledWithTabReminders());
|
||||
|
||||
if (_engagementTracker) {
|
||||
_engagementTracker->NotifyEvent(
|
||||
feature_engagement::events::kIOSOverflowMenuSetTabReminderTapped);
|
||||
}
|
||||
|
||||
// TODO(crbug.com/389912106): Display the new 'Set a Reminder' UI.
|
||||
}
|
||||
|
||||
- (OverflowMenuAction*)newClearBrowsingDataAction {
|
||||
|
@ -47685,6 +47685,8 @@ should be able to be added at any place in this file.
|
||||
label="For iOSPullToRefreshFeature feature"/>
|
||||
<suffix name="iOSReminderNotificationsOverflowMenuBubbleFeature"
|
||||
label="For iOSReminderNotificationsOverflowMenuBubbleFeature feature"/>
|
||||
<suffix name="iOSReminderNotificationsOverflowMenuNewBadgeFeature"
|
||||
label="For iOSReminderNotificationsOverflowMenuNewBadgeFeature feature"/>
|
||||
<suffix name="iOSReplaceSyncPromosWithSignInPromos"
|
||||
label="For iOSReplaceSyncPromosWithSignInPromos feature"/>
|
||||
<suffix name="iOSSavedTabGroupClosed"
|
||||
|
@ -318,6 +318,8 @@ chromium-metrics-reviews@google.com.
|
||||
summary="the full screen IPH for pull to refresh"/>
|
||||
<variant name="IPH_iOSReminderNotificationsOverflowMenuBubbleFeature"
|
||||
summary="Overflow menu bubble IPH to schedule tab reminders"/>
|
||||
<variant name="IPH_iOSReminderNotificationsOverflowMenuNewBadgeFeature"
|
||||
summary="Overflow menu new badge IPH to schedule tab reminders"/>
|
||||
<variant name="IPH_iOSReplaceSyncPromosWithSignInPromos"
|
||||
summary="account row in settings page"/>
|
||||
<variant name="IPH_iOSSavedTabGroupClosed"
|
||||
|
Reference in New Issue
Block a user