0

mahi: Add mahi educational nudge

Add nudge that educates on the Mahi feature.
https://screenshot.googleplex.com/AeiNKqinXxKruSi

The nudge will show when users visit eligible content, if:
- It hasn't been shown in the past 24 hours
- It has been shown less than three times
- Mahi feature pref is not enabled by the user

Bug: b:319732035
Change-Id: I51d3e53f7c850718c7f48fc4a54c1518b3b7d21f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5602296
Reviewed-by: James Cook <jamescook@chromium.org>
Reviewed-by: Andre Le <leandre@chromium.org>
Reviewed-by: Thanh Nguyen <thanhdng@chromium.org>
Reviewed-by: Victor Vianna <victorvianna@google.com>
Commit-Queue: Kevin Radtke <kradtke@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1315375}
This commit is contained in:
Kevin Radtke
2024-06-14 19:06:28 +00:00
committed by Chromium LUCI CQ
parent c886aa811d
commit a972bb8d4d
18 changed files with 345 additions and 10 deletions

@ -1892,6 +1892,8 @@ component("ash") {
"system/mahi/mahi_content_source_button.h",
"system/mahi/mahi_error_status_view.cc",
"system/mahi/mahi_error_status_view.h",
"system/mahi/mahi_nudge_controller.cc",
"system/mahi/mahi_nudge_controller.h",
"system/mahi/mahi_panel_drag_controller.cc",
"system/mahi/mahi_panel_drag_controller.h",
"system/mahi/mahi_panel_view.cc",
@ -4004,6 +4006,7 @@ test("ash_unittests") {
"system/lock_screen_notification_controller_unittest.cc",
"system/magic_boost/magic_boost_disclaimer_view_unittest.cc",
"system/mahi/mahi_content_source_button_unittest.cc",
"system/mahi/mahi_nudge_controller_unittest.cc",
"system/mahi/mahi_panel_drag_controller_unittest.cc",
"system/mahi/mahi_panel_view_unittest.cc",
"system/mahi/mahi_panel_widget_unittest.cc",

@ -59,6 +59,7 @@
#include "ash/system/input_device_settings/keyboard_modifier_metrics_recorder.h"
#include "ash/system/keyboard_brightness/keyboard_backlight_color_controller.h"
#include "ash/system/keyboard_brightness/keyboard_brightness_controller.h"
#include "ash/system/mahi/mahi_nudge_controller.h"
#include "ash/system/media/media_tray.h"
#include "ash/system/network/cellular_setup_notifier.h"
#include "ash/system/network/vpn_detailed_view.h"
@ -154,6 +155,7 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry,
KeyboardBacklightColorController::RegisterPrefs(registry);
KeyboardControllerImpl::RegisterProfilePrefs(registry, country);
KeyboardModifierMetricsRecorder::RegisterProfilePrefs(registry, for_test);
MahiNudgeController::RegisterProfilePrefs(registry);
MediaControllerImpl::RegisterProfilePrefs(registry);
MessageCenterController::RegisterProfilePrefs(registry);
NightLightControllerImpl::RegisterProfilePrefs(registry);

@ -5288,6 +5288,12 @@ No devices connected.
<message name="IDS_ASH_MAHI_RETRY_LINK_LABEL_TEXT" desc="Text for the link that user can retry their previous Mahi request">
Try again
</message>
<message name="IDS_ASH_MAHI_EDUCATIONAL_NUDGE_TITLE" desc="Title for the educational nudge used to discover the Mahi feature">
Right-click to summarize
</message>
<message name="IDS_ASH_MAHI_EDUCATIONAL_NUDGE_BODY" desc="Body for the educational nudge used to discover the Mahi feature">
Use Help me read to quickly summarize content or ask questions
</message>
<!-- Multi-profiles intro dialog -->
<message name="IDS_ASH_MULTIPROFILES_INTRO_HEADLINE" desc="Describes which feature multi-profiles intro dialog presents.">

@ -0,0 +1 @@
69653e00e3ef602f98f68cd361228fb47a91a19d

@ -0,0 +1 @@
69653e00e3ef602f98f68cd361228fb47a91a19d

@ -58,6 +58,12 @@ inline constexpr char kManagedOrcaEnabled[] =
// A boolean pref of whether mahi is enabled.
inline constexpr char kMahiEnabled[] = "settings.mahi_enabled";
// An integer pref that stores the times the Mahi nudge has been shown.
inline constexpr char kMahiNudgeShownCount[] = "mahi.nudge_shown_count";
// A time pref that stores the time the Mahi nudge was last shown.
inline constexpr char kMahiNudgeLastShownTime[] = "mahi.nudge_last_shown";
// An integer pref which indicates the HMR (Quick answers and Mahi) consent
// status from the user.
inline constexpr char kHMRConsentStatus[] = "settings.hmr.consent_status";

@ -245,7 +245,8 @@ enum class NudgeCatalogName {
kSearchTopRowKeyPressed = 31,
kSixPackRemappingPressed = 32,
kCapsLockShortcutPressed = 33,
kMaxValue = kCapsLockShortcutPressed
kMahi = 34,
kMaxValue = kMahi
};
// A living catalog that registers toasts.

@ -63,6 +63,7 @@
<structure type="lottie" name="IDR_BIRCH_RELEASE_NOTES_ICON" file="unscaled_resources/birch_release_notes_icon.json" compress="gzip" />
<!-- Mahi -->
<structure type="lottie" name="IDR_MAHI_GENERAL_ERROR_STATUS_IMAGE" file="unscaled_resources/mahi_general_error_status_image.json" compress="gzip" />
<structure type="lottie" name="IDR_MAHI_EDUCATIONAL_NUDGE_IMAGE" file="unscaled_resources/mahi_educational_nudge_image.json" compress="gzip" />
<!-- Magic Boost -->
<structure type="lottie" name="IDR_MAGIC_BOOST_DISCLAIMER_ILLUSTRATION" file="unscaled_resources/magic_boost_disclaimer_image.json" compress="gzip" />
<!-- Shortcut Nudge -->

File diff suppressed because one or more lines are too long

@ -5,6 +5,7 @@
#ifndef ASH_SYSTEM_MAHI_MAHI_CONSTANTS_H_
#define ASH_SYSTEM_MAHI_MAHI_CONSTANTS_H_
#include "base/time/time.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/highlight_border.h"
@ -73,6 +74,11 @@ inline constexpr int kFakeMahiManagerLoadAnswerDelaySeconds = 3;
inline constexpr int kFakeMahiManagerLoadSummaryDelaySeconds = 4;
inline constexpr int kFakeMahiManagerLoadOutlinesDelaySeconds = 6;
// Nudge constants
inline constexpr char kMahiNudgeId[] = "mahi.nudge";
inline constexpr base::TimeDelta kNudgeTimeBetweenShown = base::Hours(24);
inline constexpr int kNudgeMaxShownCount = 3;
// Metrics
// Contains the types of button existed in Mahi Panel widget. Note: this should
// be kept in sync with `PanelButton` enum in

@ -0,0 +1,80 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/mahi/mahi_nudge_controller.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/constants/notifier_catalogs.h"
#include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h"
#include "ash/public/cpp/system/anchored_nudge_data.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/mahi/mahi_constants.h"
#include "ash/system/toast/anchored_nudge_manager_impl.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "ui/base/l10n/l10n_util.h"
namespace ash {
namespace {
PrefService* GetPrefService() {
return Shell::Get()->session_controller()->GetActivePrefService();
}
} // namespace
MahiNudgeController::MahiNudgeController() = default;
MahiNudgeController::~MahiNudgeController() = default;
// static
void MahiNudgeController::RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterIntegerPref(
prefs::kMahiNudgeShownCount, 0,
user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
registry->RegisterTimePref(prefs::kMahiNudgeLastShownTime, base::Time());
}
void MahiNudgeController::MaybeShowNudge() {
auto* pref_service = GetPrefService();
// Don't show nudge if the feature has been enabled by the user.
if (pref_service->GetBoolean(prefs::kMahiEnabled)) {
return;
}
// Nudge has been shown three times. No need to educate anymore.
const int shown_count = pref_service->GetInteger(prefs::kMahiNudgeShownCount);
if (shown_count >= mahi_constants::kNudgeMaxShownCount) {
return;
}
// Don't show nudge if it was shown within the last 24 hours.
if (base::Time::Now() -
pref_service->GetTime(prefs::kMahiNudgeLastShownTime) <
mahi_constants::kNudgeTimeBetweenShown) {
return;
}
AnchoredNudgeData nudge_data(
mahi_constants::kMahiNudgeId, NudgeCatalogName::kMahi,
/*body_text=*/
l10n_util::GetStringUTF16(IDS_ASH_MAHI_EDUCATIONAL_NUDGE_BODY));
nudge_data.title_text =
l10n_util::GetStringUTF16(IDS_ASH_MAHI_EDUCATIONAL_NUDGE_TITLE);
nudge_data.image_model =
ui::ResourceBundle::GetSharedInstance().GetThemedLottieImageNamed(
IDR_MAHI_EDUCATIONAL_NUDGE_IMAGE);
Shell::Get()->anchored_nudge_manager()->Show(nudge_data);
// Update nudge prefs.
pref_service->SetInteger(prefs::kMahiNudgeShownCount, shown_count + 1);
pref_service->SetTime(prefs::kMahiNudgeLastShownTime, base::Time::Now());
}
} // namespace ash

@ -0,0 +1,31 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_SYSTEM_MAHI_MAHI_NUDGE_CONTROLLER_H_
#define ASH_SYSTEM_MAHI_MAHI_NUDGE_CONTROLLER_H_
#include "ash/ash_export.h"
class PrefRegistrySimple;
namespace ash {
// Controller for showing the educational nudge for the "Help me read" feature.
class ASH_EXPORT MahiNudgeController {
public:
MahiNudgeController();
MahiNudgeController(const MahiNudgeController&) = delete;
MahiNudgeController& operator=(const MahiNudgeController&) = delete;
~MahiNudgeController();
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
// Attempts to show the nudge. The nudge will show if it hasn't been shown in
// the past 24 hours, or if it has been shown less than three times.
void MaybeShowNudge();
};
} // namespace ash
#endif // ASH_SYSTEM_MAHI_MAHI_NUDGE_CONTROLLER_H_

@ -0,0 +1,139 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/mahi/mahi_nudge_controller.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/system/mahi/mahi_constants.h"
#include "ash/system/toast/anchored_nudge_manager_impl.h"
#include "ash/test/ash_test_base.h"
#include "base/time/time.h"
#include "base/time/time_override.h"
#include "components/prefs/pref_service.h"
#include "ui/lottie/resource.h"
namespace ash {
namespace {
void SetMahiEnabledByUserPref(bool enabled) {
Shell::Get()->session_controller()->GetActivePrefService()->SetBoolean(
ash::prefs::kMahiEnabled, enabled);
}
bool IsMahiNudgeShown() {
return Shell::Get()->anchored_nudge_manager()->IsNudgeShown(
mahi_constants::kMahiNudgeId);
}
} // namespace
class MahiNudgeControllerTest : public AshTestBase {
public:
MahiNudgeControllerTest() {
mahi_nudge_controller_ = std::make_unique<MahiNudgeController>();
// Sets the default functions for the test to create image with the lottie
// resource id. Otherwise there's no `g_parse_lottie_as_still_image_` set in
// the `ResourceBundle`.
ui::ResourceBundle::SetLottieParsingFunctions(
&lottie::ParseLottieAsStillImage,
&lottie::ParseLottieAsThemedStillImage);
}
MahiNudgeController* nudge_controller() {
return mahi_nudge_controller_.get();
}
AnchoredNudgeManagerImpl* nudge_manager() {
return Shell::Get()->anchored_nudge_manager();
}
static base::Time GetTestTime() { return test_time_; }
static void SetTestTime(base::Time test_time) { test_time_ = test_time; }
private:
std::unique_ptr<MahiNudgeController> mahi_nudge_controller_;
static inline base::Time test_time_;
};
// Tests that the nudge can show when the user is not opted into Mahi.
TEST_F(MahiNudgeControllerTest, NudgeShows_WhenUserPrefNotEnabled) {
SetMahiEnabledByUserPref(false);
EXPECT_FALSE(IsMahiNudgeShown());
nudge_controller()->MaybeShowNudge();
EXPECT_TRUE(IsMahiNudgeShown());
}
// Tests that the nudge won't show when the user has opted into Mahi.
TEST_F(MahiNudgeControllerTest, NudgeDoesNotShow_WhenUserPrefEnabled) {
SetMahiEnabledByUserPref(true);
EXPECT_FALSE(IsMahiNudgeShown());
nudge_controller()->MaybeShowNudge();
EXPECT_FALSE(IsMahiNudgeShown());
}
// Tests that the nudge won't show if the time between shown threshold hasn't
// passed since it was last shown.
TEST_F(MahiNudgeControllerTest, NudgeDoesNotShow_IfRecentlyShown) {
SetMahiEnabledByUserPref(false);
SetTestTime(base::Time::Now());
base::subtle::ScopedTimeClockOverrides clock_override(
/*time_override=*/&MahiNudgeControllerTest::GetTestTime,
/*time_ticks_override=*/nullptr, /*thread_ticks_override=*/nullptr);
// Show the nudge once and close it.
EXPECT_FALSE(IsMahiNudgeShown());
nudge_controller()->MaybeShowNudge();
EXPECT_TRUE(IsMahiNudgeShown());
nudge_manager()->Cancel(mahi_constants::kMahiNudgeId);
// Attempt showing the nudge again immediately. It should not show.
nudge_controller()->MaybeShowNudge();
EXPECT_FALSE(IsMahiNudgeShown());
// Attempt showing the nudge after some time but before its threshold time has
// fully passed. It should not show.
SetTestTime(GetTestTime() + mahi_constants::kNudgeTimeBetweenShown -
base::Hours(1));
nudge_controller()->MaybeShowNudge();
EXPECT_FALSE(IsMahiNudgeShown());
// Attempt showing the nudge after its "time between shown" threshold has
// passed. It should show.
SetTestTime(GetTestTime() + mahi_constants::kNudgeTimeBetweenShown +
base::Hours(1));
nudge_controller()->MaybeShowNudge();
EXPECT_TRUE(IsMahiNudgeShown());
}
// Tests that the nudge won't show if it has been shown its max number of times.
TEST_F(MahiNudgeControllerTest, NudgeDoesNotShow_IfMaxTimesShown) {
SetMahiEnabledByUserPref(false);
SetTestTime(base::Time::Now());
base::subtle::ScopedTimeClockOverrides clock_override(
/*time_override=*/&MahiNudgeControllerTest::GetTestTime,
/*time_ticks_override=*/nullptr, /*thread_ticks_override=*/nullptr);
// Show the nudge its max number of times.
for (int i = 0; i < mahi_constants::kNudgeMaxShownCount; i++) {
nudge_controller()->MaybeShowNudge();
EXPECT_TRUE(IsMahiNudgeShown());
nudge_manager()->Cancel(mahi_constants::kMahiNudgeId);
SetTestTime(GetTestTime() + mahi_constants::kNudgeTimeBetweenShown +
base::Hours(1));
}
// Attempt showing the nudge once more. It should not show.
nudge_controller()->MaybeShowNudge();
EXPECT_FALSE(IsMahiNudgeShown());
}
} // namespace ash

@ -13,6 +13,7 @@
#include "ash/constants/ash_pref_names.h"
#include "ash/shell.h"
#include "ash/system/mahi/mahi_nudge_controller.h"
#include "ash/system/mahi/mahi_ui_controller.h"
#include "ash/webui/settings/public/constants/routes.mojom.h"
#include "ash/webui/settings/public/constants/setting.mojom.h"
@ -108,7 +109,8 @@ std::unique_ptr<manta::MahiProvider> CreateProvider() {
namespace ash {
MahiManagerImpl::MahiManagerImpl()
: cache_manager_(std::make_unique<MahiCacheManager>()) {
: cache_manager_(std::make_unique<MahiCacheManager>()),
mahi_nudge_controller_(std::make_unique<MahiNudgeController>()) {
session_observation_.Observe(Shell::Get()->session_controller());
PrefService* last_active_user_pref_service =
Shell::Get()->session_controller()->GetLastActiveUserPrefService();
@ -435,6 +437,11 @@ void MahiManagerImpl::NotifyRefreshAvailability(bool available) {
if (ui_controller_.IsMahiPanelOpen()) {
ui_controller_.NotifyRefreshAvailabilityChanged(available);
}
// Attempt showing an educational nudge when users visit eligible content.
if (available) {
mahi_nudge_controller_->MaybeShowNudge();
}
}
void MahiManagerImpl::OnActiveUserPrefServiceChanged(

@ -23,6 +23,8 @@
namespace ash {
class MahiNudgeController;
// Implementation of `MahiManager`.
class MahiManagerImpl : public chromeos::MahiManager, public SessionObserver {
public:
@ -54,8 +56,7 @@ class MahiManagerImpl : public chromeos::MahiManager, public SessionObserver {
const base::UnguessableToken media_app_client_id) override;
std::optional<base::UnguessableToken> GetMediaAppPDFClientId() const override;
// Notifies the panel that refresh is available or not for the corresponding
// surface.
// Called when availability for a refresh changes based on the shown content.
void NotifyRefreshAvailability(bool available);
// SessionObserver:
@ -128,6 +129,8 @@ class MahiManagerImpl : public chromeos::MahiManager, public SessionObserver {
std::unique_ptr<MahiCacheManager> cache_manager_;
std::unique_ptr<MahiNudgeController> mahi_nudge_controller_;
// If true, tries to get content from MediaAppContentManager instead.
bool media_app_pdf_focused_ = false;
base::UnguessableToken media_app_client_id_;

@ -10,6 +10,8 @@
#include "ash/constants/ash_pref_names.h"
#include "ash/constants/ash_switches.h"
#include "ash/shell.h"
#include "ash/system/mahi/mahi_constants.h"
#include "ash/system/toast/anchored_nudge_manager_impl.h"
#include "ash/test/ash_test_base.h"
#include "base/auto_reset.h"
#include "base/command_line.h"
@ -29,9 +31,11 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/lottie/resource.h"
#include "ui/views/widget/widget.h"
namespace {
using ::testing::IsNull;
constexpr char kFakeSummary[] = "Fake summary";
@ -56,6 +60,12 @@ class FakeMahiProvider : public manta::MahiProvider {
private:
int num_summarize_call_ = 0;
};
bool IsMahiNudgeShown() {
return ash::Shell::Get()->anchored_nudge_manager()->IsNudgeShown(
ash::mahi_constants::kMahiNudgeId);
}
} // namespace
namespace ash {
@ -64,7 +74,14 @@ class MahiManagerImplTest : public NoSessionAshTestBase {
public:
MahiManagerImplTest()
: NoSessionAshTestBase(
base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
// Sets the default functions for the test to create image with the lottie
// resource id. Otherwise there's no `g_parse_lottie_as_still_image_` set in
// the `ResourceBundle`.
ui::ResourceBundle::SetLottieParsingFunctions(
&lottie::ParseLottieAsStillImage,
&lottie::ParseLottieAsThemedStillImage);
}
MahiManagerImplTest(const MahiManagerImplTest&) = delete;
MahiManagerImplTest& operator=(const MahiManagerImplTest&) = delete;
@ -90,7 +107,7 @@ class MahiManagerImplTest : public NoSessionAshTestBase {
NoSessionAshTestBase::TearDown();
}
void SetUserPref(bool enabled) {
void SetMahiEnabledByUserPref(bool enabled) {
Shell::Get()->session_controller()->GetActivePrefService()->SetBoolean(
ash::prefs::kMahiEnabled, enabled);
}
@ -115,6 +132,10 @@ class MahiManagerImplTest : public NoSessionAshTestBase {
return mahi_manager_impl_->cache_manager_.get();
}
void NotifyRefreshAvailability(bool available) {
mahi_manager_impl_->NotifyRefreshAvailability(available);
}
void RequestSummary() {
// Sets the page that needed to get summary.
mahi_manager_impl_->SetCurrentFocusedPageInfo(
@ -185,7 +206,7 @@ TEST_F(MahiManagerImplTest, TurnOffSettingsClearCache) {
EXPECT_EQ(GetCacheManager()->size(), 1);
// Cache must be empty after user turn off the settings.
SetUserPref(false);
SetMahiEnabledByUserPref(false);
EXPECT_EQ(GetCacheManager()->size(), 0);
}
@ -194,14 +215,14 @@ TEST_F(MahiManagerImplTest, SetMahiPrefOnLogin) {
// true or false.
for (bool mahi_enabled : {false, true}) {
// Sets the pref for the default user.
SetUserPref(mahi_enabled);
SetMahiEnabledByUserPref(mahi_enabled);
ASSERT_EQ(IsEnabled(), mahi_enabled);
const AccountId user1_account_id =
Shell::Get()->session_controller()->GetActiveAccountId();
// Sets the pref for the second user.
SimulateUserLogin("other@user.test");
SetUserPref(!mahi_enabled);
SetMahiEnabledByUserPref(!mahi_enabled);
EXPECT_EQ(IsEnabled(), !mahi_enabled);
// Switching back to the previous user will update to correct pref.
@ -216,11 +237,31 @@ TEST_F(MahiManagerImplTest, SetMahiPrefOnLogin) {
TEST_F(MahiManagerImplTest, OnPreferenceChanged) {
for (bool mahi_enabled : {false, true, false}) {
SetUserPref(mahi_enabled);
SetMahiEnabledByUserPref(mahi_enabled);
EXPECT_EQ(IsEnabled(), mahi_enabled);
}
}
// Tests that the Mahi educational nudge is shown when the user visits eligible
// content and they have not opted in to the feature.
TEST_F(MahiManagerImplTest, ShowEducationalNudge) {
SetMahiEnabledByUserPref(false);
EXPECT_FALSE(IsMahiNudgeShown());
// Notifying that a refresh is not available should have no effect.
NotifyRefreshAvailability(/*available=*/false);
EXPECT_FALSE(IsMahiNudgeShown());
// Notifying that a refresh is available should show the nudge.
NotifyRefreshAvailability(/*available=*/true);
EXPECT_TRUE(IsMahiNudgeShown());
// Notifying that a refresh is not available should have no effect.
NotifyRefreshAvailability(/*available=*/false);
EXPECT_TRUE(IsMahiNudgeShown());
}
class MahiManagerImplFeatureKeyTest : public NoSessionAshTestBase {
public:
MahiManagerImplFeatureKeyTest() {

@ -350,6 +350,7 @@ enum {
kDesktopToiOSAddressPromoLastImpressionTimestamp = 100291,
kDesktopToiOSAddressPromoImpressionsCounter = 100292,
kDesktopToiOSAddressPromoOptOut = 100293,
kMahiNudgeShownCount = 100294,
// See components/sync_preferences/README.md about adding new entries here.
// vvvvv IMPORTANT! vvvvv
// Note to the reviewer: IT IS YOUR RESPONSIBILITY to ensure that new syncable
@ -1177,6 +1178,10 @@ constexpr auto kChromeSyncablePrefsAllowlist = base::MakeFixedFlatMap<
{syncable_prefs_ids::kShelfMallAppPinRolls, syncer::OS_PREFERENCES,
sync_preferences::PrefSensitivity::kNone,
sync_preferences::MergeBehavior::kMergeableListWithRewriteOnUpdate}},
{ash::prefs::kMahiNudgeShownCount,
{syncable_prefs_ids::kMahiNudgeShownCount, syncer::OS_PREFERENCES,
sync_preferences::PrefSensitivity::kNone,
sync_preferences::MergeBehavior::kNone}},
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
{performance_manager::user_tuning::prefs::kTabDiscardingExceptions,
{syncable_prefs_ids::kTabDiscardingExceptions, syncer::PREFERENCES,

@ -620,6 +620,7 @@ chromium-metrics-reviews@google.com.
<int value="100291" label="iOSAddressPromoLastImpressionTimestamp"/>
<int value="100292" label="iOSAddressPromoImpressionsCounter"/>
<int value="100293" label="iOSAddressPromoOptOut"/>
<int value="100294" label="MahiNudgeShownCount"/>
<!-- LINT.ThenChange(/chrome/browser/sync/prefs/chrome_syncable_prefs_database.cc:ChromeSyncablePref)-->
<!-- LINT.IfChange(IosSyncablePref) -->