From bcccd565a497dd93460427de2bcfe724b646f3fe Mon Sep 17 00:00:00 2001
From: Vishwas Uppoor <vishwasuppoor@google.com>
Date: Wed, 8 Jun 2022 18:43:21 +0000
Subject: [PATCH] [Offers] Migrate Offer Notification Infobar to a Message

Offers linked to payment methods on merchant sites are currently shown on an infobar. This CL shows the offers on a Message.

Screenshot: https://screenshot.googleplex.com/axzyJjH4NPUuhXZ

Bug: 1323077
Change-Id: I8362f4d770571d2b29b25c82e63e39caf65d0675

Validate-Test-Flakiness: skip
Change-Id: I8362f4d770571d2b29b25c82e63e39caf65d0675
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3655680
Reviewed-by: Siyu An <siyua@chromium.org>
Reviewed-by: Evan Stade <estade@chromium.org>
Commit-Queue: Vishwas Uppoor <vishwasuppoor@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1012077}
---
 chrome/browser/ui/BUILD.gn                    |   4 +-
 .../ui/autofill/chrome_autofill_client.cc     |  13 +-
 .../offer_notification_controller_android.cc  | 117 +++++++++++
 .../offer_notification_controller_android.h   |  57 ++++++
 ...ication_controller_android_browsertest.cc} | 183 +++++++++++++-----
 ...er_notification_infobar_controller_impl.cc |  50 -----
 ...fer_notification_infobar_controller_impl.h |  44 -----
 chrome/test/BUILD.gn                          |   2 +-
 .../browser/payments/autofill_offer_manager.h |   2 +-
 components/autofill_payments_strings.grdp     |  11 +-
 ...L_OFFERS_MESSAGE_DESCRIPTION_TEXT.png.sha1 |   1 +
 ...FFERS_MESSAGE_PRIMARY_BUTTON_TEXT.png.sha1 |   1 +
 ...IDS_AUTOFILL_OFFERS_MESSAGE_TITLE.png.sha1 |   1 +
 13 files changed, 329 insertions(+), 157 deletions(-)
 create mode 100644 chrome/browser/ui/autofill/payments/offer_notification_controller_android.cc
 create mode 100644 chrome/browser/ui/autofill/payments/offer_notification_controller_android.h
 rename chrome/browser/ui/autofill/payments/{offer_notification_infobar_controller_impl_browsertest.cc => offer_notification_controller_android_browsertest.cc} (66%)
 delete mode 100644 chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.cc
 delete mode 100644 chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.h
 create mode 100644 components/autofill_payments_strings_grdp/IDS_AUTOFILL_OFFERS_MESSAGE_DESCRIPTION_TEXT.png.sha1
 create mode 100644 components/autofill_payments_strings_grdp/IDS_AUTOFILL_OFFERS_MESSAGE_PRIMARY_BUTTON_TEXT.png.sha1
 create mode 100644 components/autofill_payments_strings_grdp/IDS_AUTOFILL_OFFERS_MESSAGE_TITLE.png.sha1

diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index efc65cf08595f..14bcf1d7aebb8 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -864,8 +864,8 @@ static_library("ui") {
       "autofill/payments/autofill_snackbar_controller_impl.cc",
       "autofill/payments/autofill_snackbar_controller_impl.h",
       "autofill/payments/autofill_snackbar_view.h",
-      "autofill/payments/offer_notification_infobar_controller_impl.cc",
-      "autofill/payments/offer_notification_infobar_controller_impl.h",
+      "autofill/payments/offer_notification_controller_android.cc",
+      "autofill/payments/offer_notification_controller_android.h",
       "autofill/payments/virtual_card_enroll_bubble_controller_impl.cc",
       "autofill/payments/virtual_card_enroll_bubble_controller_impl.h",
       "browser_otr_state_android.cc",
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index 9debc89c913c7..13c9f769fe9ed 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -95,7 +95,7 @@
 #include "chrome/browser/ui/android/autofill/card_name_fix_flow_view_android.h"
 #include "chrome/browser/ui/android/infobars/autofill_credit_card_filling_infobar.h"
 #include "chrome/browser/ui/android/infobars/autofill_offer_notification_infobar.h"
-#include "chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.h"
+#include "chrome/browser/ui/autofill/payments/offer_notification_controller_android.h"
 #include "components/autofill/core/browser/payments/autofill_credit_card_filling_infobar_delegate_mobile.h"
 #include "components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.h"
 #include "components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h"
@@ -793,8 +793,9 @@ void ChromeAutofillClient::UpdateOfferNotification(
     // it again.
     return;
   }
-  std::unique_ptr<OfferNotificationInfoBarControllerImpl> controller =
-      std::make_unique<OfferNotificationInfoBarControllerImpl>(web_contents());
+  OfferNotificationControllerAndroid::CreateForWebContents(web_contents());
+  OfferNotificationControllerAndroid* controller =
+      OfferNotificationControllerAndroid::FromWebContents(web_contents());
   controller->ShowIfNecessary(offer, card);
 #else
   OfferNotificationBubbleControllerImpl::CreateForWebContents(web_contents());
@@ -807,9 +808,9 @@ void ChromeAutofillClient::UpdateOfferNotification(
 
 void ChromeAutofillClient::DismissOfferNotification() {
 #if BUILDFLAG(IS_ANDROID)
-  std::unique_ptr<OfferNotificationInfoBarControllerImpl> controller =
-      std::make_unique<OfferNotificationInfoBarControllerImpl>(web_contents());
-  DCHECK(controller);
+  OfferNotificationControllerAndroid::CreateForWebContents(web_contents());
+  OfferNotificationControllerAndroid* controller =
+      OfferNotificationControllerAndroid::FromWebContents(web_contents());
   controller->Dismiss();
 #else
   OfferNotificationBubbleControllerImpl* controller =
diff --git a/chrome/browser/ui/autofill/payments/offer_notification_controller_android.cc b/chrome/browser/ui/autofill/payments/offer_notification_controller_android.cc
new file mode 100644
index 0000000000000..4af71477dd6c5
--- /dev/null
+++ b/chrome/browser/ui/autofill/payments/offer_notification_controller_android.cc
@@ -0,0 +1,117 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/autofill/payments/offer_notification_controller_android.h"
+
+#include <memory>
+
+#include "chrome/browser/android/resource_mapper.h"
+#include "chrome/browser/ui/android/infobars/autofill_offer_notification_infobar.h"
+#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
+#include "components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.h"
+#include "components/grit/components_scaled_resources.h"
+#include "components/infobars/content/content_infobar_manager.h"
+#include "components/infobars/core/infobar.h"
+#include "components/messages/android/message_dispatcher_bridge.h"
+#include "components/messages/android/message_enums.h"
+#include "components/messages/android/messages_feature.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/android/window_android.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace autofill {
+
+OfferNotificationControllerAndroid::OfferNotificationControllerAndroid(
+    content::WebContents* web_contents)
+    : content::WebContentsUserData<OfferNotificationControllerAndroid>(
+          *web_contents) {}
+
+OfferNotificationControllerAndroid::~OfferNotificationControllerAndroid() {
+  DismissMessage();
+}
+
+void OfferNotificationControllerAndroid::ShowIfNecessary(
+    const AutofillOfferData* offer,
+    const CreditCard* card) {
+  DCHECK(offer);
+  if (!card)
+    return;
+
+  if (messages::IsOfferNotificationMessagesUiEnabled()) {
+    if (message_) {
+      // Dismiss the currently-shown message so that the new one can be
+      // displayed.
+      DismissMessage();
+    }
+    message_ = std::make_unique<messages::MessageWrapper>(
+        messages::MessageIdentifier::OFFER_NOTIFICATION,
+        base::BindOnce(&OfferNotificationControllerAndroid::HandleMessageAction,
+                       base::Unretained(this), offer->GetOfferDetailsUrl()),
+        base::BindOnce(
+            &OfferNotificationControllerAndroid::HandleMessageDismiss,
+            base::Unretained(this)));
+    message_->SetTitle(
+        l10n_util::GetStringUTF16(IDS_AUTOFILL_OFFERS_MESSAGE_TITLE));
+    message_->SetDescription(l10n_util::GetStringFUTF16(
+        IDS_AUTOFILL_OFFERS_MESSAGE_DESCRIPTION_TEXT,
+        card->CardIdentifierStringForAutofillDisplay()));
+    message_->SetIconResourceId(
+        ResourceMapper::MapToJavaDrawableId(IDR_AUTOFILL_GOOGLE_PAY));
+    message_->DisableIconTint();
+    message_->SetPrimaryButtonText(l10n_util::GetStringUTF16(
+        IDS_AUTOFILL_OFFERS_MESSAGE_PRIMARY_BUTTON_TEXT));
+    messages::MessageDispatcherBridge::Get()->EnqueueMessage(
+        message_.get(), &GetWebContents(),
+        messages::MessageScopeType::WEB_CONTENTS,
+        messages::MessagePriority::kNormal);
+  } else {
+    infobars::ContentInfoBarManager::FromWebContents(&GetWebContents())
+        ->AddInfoBar(std::make_unique<AutofillOfferNotificationInfoBar>(
+            std::make_unique<AutofillOfferNotificationInfoBarDelegateMobile>(
+                offer->GetOfferDetailsUrl(), *card)));
+  }
+}
+
+void OfferNotificationControllerAndroid::Dismiss() {
+  if (messages::IsOfferNotificationMessagesUiEnabled()) {
+    DismissMessage();
+  } else {
+    infobars::ContentInfoBarManager* content_infobar_manager =
+        infobars::ContentInfoBarManager::FromWebContents(&GetWebContents());
+    if (!content_infobar_manager)
+      return;
+
+    for (size_t i = 0; i < content_infobar_manager->infobar_count(); ++i) {
+      infobars::InfoBar* infobar = content_infobar_manager->infobar_at(i);
+      if (infobar->delegate()->GetIdentifier() ==
+          infobars::InfoBarDelegate::
+              AUTOFILL_OFFER_NOTIFICATION_INFOBAR_DELEGATE) {
+        content_infobar_manager->RemoveInfoBar(infobar);
+        return;
+      }
+    }
+  }
+}
+
+void OfferNotificationControllerAndroid::DismissMessage() {
+  if (message_) {
+    messages::MessageDispatcherBridge::Get()->DismissMessage(
+        message_.get(), messages::DismissReason::UNKNOWN);
+  }
+}
+
+void OfferNotificationControllerAndroid::HandleMessageAction(const GURL& url) {
+  GetWebContents().OpenURL(content::OpenURLParams(
+      url, content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      ui::PAGE_TRANSITION_LINK, false));
+}
+
+void OfferNotificationControllerAndroid::HandleMessageDismiss(
+    messages::DismissReason dismiss_reason) {
+  message_.reset();
+}
+
+WEB_CONTENTS_USER_DATA_KEY_IMPL(OfferNotificationControllerAndroid);
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/autofill/payments/offer_notification_controller_android.h b/chrome/browser/ui/autofill/payments/offer_notification_controller_android.h
new file mode 100644
index 0000000000000..e9df765ed4eda
--- /dev/null
+++ b/chrome/browser/ui/autofill/payments/offer_notification_controller_android.h
@@ -0,0 +1,57 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_OFFER_NOTIFICATION_CONTROLLER_ANDROID_H_
+#define CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_OFFER_NOTIFICATION_CONTROLLER_ANDROID_H_
+
+#include "base/memory/raw_ptr.h"
+#include "components/autofill/core/browser/data_model/credit_card.h"
+#include "components/messages/android/message_wrapper.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+namespace autofill {
+
+class AutofillOfferData;
+
+// Per-tab controller to control the offer notification infobar / message
+// displayed on mobile.
+class OfferNotificationControllerAndroid
+    : public content::WebContentsUserData<OfferNotificationControllerAndroid> {
+ public:
+  explicit OfferNotificationControllerAndroid(
+      content::WebContents* web_contents);
+  ~OfferNotificationControllerAndroid() override;
+
+  OfferNotificationControllerAndroid(
+      const OfferNotificationControllerAndroid&) = delete;
+  OfferNotificationControllerAndroid& operator=(
+      const OfferNotificationControllerAndroid&) = delete;
+
+  // Show the infobar / message unless it was already shown in the same tab with
+  // the same origin.
+  void ShowIfNecessary(const AutofillOfferData* offer, const CreditCard* card);
+
+  // Dismiss the infobar / message if it is visible.
+  void Dismiss();
+
+ private:
+  friend class content::WebContentsUserData<OfferNotificationControllerAndroid>;
+
+  // Dismiss the message if it is visible.
+  void DismissMessage();
+
+  // Callbacks for user selection on offer notification message.
+  void HandleMessageAction(const GURL& url);
+  void HandleMessageDismiss(messages::DismissReason dismiss_reason);
+
+  // Delegate of a toast style popup showing in the top of the screen.
+  std::unique_ptr<messages::MessageWrapper> message_;
+
+  WEB_CONTENTS_USER_DATA_KEY_DECL();
+};
+
+}  // namespace autofill
+
+#endif  // CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_OFFER_NOTIFICATION_CONTROLLER_ANDROID_H_
diff --git a/chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl_browsertest.cc b/chrome/browser/ui/autofill/payments/offer_notification_controller_android_browsertest.cc
similarity index 66%
rename from chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl_browsertest.cc
rename to chrome/browser/ui/autofill/payments/offer_notification_controller_android_browsertest.cc
index ffd6436a13bca..35246819d8089 100644
--- a/chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl_browsertest.cc
+++ b/chrome/browser/ui/autofill/payments/offer_notification_controller_android_browsertest.cc
@@ -3,10 +3,11 @@
 // found in the LICENSE file.
 
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/autofill/autofill_uitest_util.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.h"
+#include "chrome/browser/ui/autofill/payments/offer_notification_controller_android.h"
 #include "chrome/test/base/android/android_browser_test.h"
 #include "chrome/test/base/chrome_test_utils.h"
 #include "components/autofill/content/browser/content_autofill_driver.h"
@@ -19,6 +20,9 @@
 #include "components/infobars/content/content_infobar_manager.h"
 #include "components/infobars/core/infobar.h"
 #include "components/infobars/core/infobar_delegate.h"
+#include "components/messages/android/message_enums.h"
+#include "components/messages/android/messages_feature.h"
+#include "components/messages/android/test/messages_test_helper.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
@@ -29,11 +33,11 @@ namespace autofill {
 
 const char kHostName[] = "example.com";
 
-class OfferNotificationInfoBarControllerImplBrowserTest
+class OfferNotificationControllerAndroidBrowserTest
     : public AndroidBrowserTest {
  public:
-  OfferNotificationInfoBarControllerImplBrowserTest() = default;
-  ~OfferNotificationInfoBarControllerImplBrowserTest() override = default;
+  OfferNotificationControllerAndroidBrowserTest() = default;
+  ~OfferNotificationControllerAndroidBrowserTest() override = default;
 
   void SetUp() override {
     AndroidBrowserTest::SetUp();
@@ -44,30 +48,6 @@ class OfferNotificationInfoBarControllerImplBrowserTest
     return chrome_test_utils::GetActiveWebContents(this);
   }
 
-  infobars::InfoBar* GetInfoBar() {
-    infobars::ContentInfoBarManager* infobar_manager =
-        infobars::ContentInfoBarManager::FromWebContents(GetWebContents());
-    for (size_t i = 0; i < infobar_manager->infobar_count(); ++i) {
-      infobars::InfoBar* infobar = infobar_manager->infobar_at(i);
-      if (infobar->delegate()->GetIdentifier() ==
-          infobars::InfoBarDelegate::
-              AUTOFILL_OFFER_NOTIFICATION_INFOBAR_DELEGATE) {
-        return infobar;
-      }
-    }
-    return nullptr;
-  }
-
-  AutofillOfferNotificationInfoBarDelegateMobile* GetInfoBarDelegate(
-      infobars::InfoBar* infobar) {
-    return static_cast<AutofillOfferNotificationInfoBarDelegateMobile*>(
-        infobar->delegate());
-  }
-
-  void ShowOfferNotificationInfoBar(const AutofillOfferData* offer) {
-    offer_notification_infobar_controller_->ShowIfNecessary(offer, &card_);
-  }
-
   AutofillOfferData CreateTestCardLinkedOffer(
       const std::vector<GURL>& merchant_origins,
       const std::vector<int64_t>& eligible_instrument_ids,
@@ -81,19 +61,6 @@ class OfferNotificationInfoBarControllerImplBrowserTest
         offer_reward_amount);
   }
 
-  void VerifyInfoBarShownCount(int count) {
-    histogram_tester_.ExpectTotalCount(
-        "Autofill.OfferNotificationInfoBarOffer.CardLinkedOffer", count);
-  }
-
-  void VerifyInfoBarResultMetric(
-      AutofillMetrics::OfferNotificationInfoBarResultMetric metric,
-      int count) {
-    histogram_tester_.ExpectBucketCount(
-        "Autofill.OfferNotificationInfoBarResult.CardLinkedOffer", metric,
-        count);
-  }
-
   GURL GetInitialUrl() {
     return embedded_test_server()->GetURL(kHostName, "/empty.html");
   }
@@ -104,9 +71,8 @@ class OfferNotificationInfoBarControllerImplBrowserTest
     // Wait for Personal Data Manager to be fully loaded to prevent that
     // spurious notifications deceive the tests.
     WaitForPersonalDataManagerToBeLoaded(GetProfile());
-    offer_notification_infobar_controller_ =
-        std::make_unique<OfferNotificationInfoBarControllerImpl>(
-            GetWebContents());
+    offer_notification_controller_android_ =
+        std::make_unique<OfferNotificationControllerAndroid>(GetWebContents());
     host_resolver()->AddRule("*", "127.0.0.1");
     embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
     ASSERT_TRUE(embedded_test_server()->Start());
@@ -150,17 +116,70 @@ class OfferNotificationInfoBarControllerImplBrowserTest
     handler->AddShownNotificationIdForTesting(id);
   }
 
- private:
-  std::unique_ptr<OfferNotificationInfoBarControllerImpl>
-      offer_notification_infobar_controller_;
-  // CreditCard that is linked to the offer displayed in the offer notification
-  // infobar.
+ protected:
+  std::unique_ptr<OfferNotificationControllerAndroid>
+      offer_notification_controller_android_;
+  // CreditCard that is linked to the offer displayed in the offer notification.
   CreditCard card_;
   base::HistogramTester histogram_tester_;
+  base::test::ScopedFeatureList scoped_feature_list_;
+
+ private:
   PersonalDataManager* personal_data_;
 };
 
-IN_PROC_BROWSER_TEST_F(OfferNotificationInfoBarControllerImplBrowserTest,
+class OfferNotificationControllerAndroidBrowserTestForInfobar
+    : public OfferNotificationControllerAndroidBrowserTest {
+ public:
+  OfferNotificationControllerAndroidBrowserTestForInfobar() = default;
+
+  void SetUp() override {
+    scoped_feature_list_.InitWithFeatures(
+        /*enabled_features=*/{},
+        /*disabled_features=*/{messages::kMessagesForAndroidInfrastructure,
+                               messages::kMessagesForAndroidOfferNotification});
+    OfferNotificationControllerAndroidBrowserTest::SetUp();
+  }
+
+  infobars::InfoBar* GetInfoBar() {
+    infobars::ContentInfoBarManager* infobar_manager =
+        infobars::ContentInfoBarManager::FromWebContents(GetWebContents());
+    for (size_t i = 0; i < infobar_manager->infobar_count(); ++i) {
+      infobars::InfoBar* infobar = infobar_manager->infobar_at(i);
+      if (infobar->delegate()->GetIdentifier() ==
+          infobars::InfoBarDelegate::
+              AUTOFILL_OFFER_NOTIFICATION_INFOBAR_DELEGATE) {
+        return infobar;
+      }
+    }
+    return nullptr;
+  }
+
+  AutofillOfferNotificationInfoBarDelegateMobile* GetInfoBarDelegate(
+      infobars::InfoBar* infobar) {
+    return static_cast<AutofillOfferNotificationInfoBarDelegateMobile*>(
+        infobar->delegate());
+  }
+
+  void ShowOfferNotificationInfoBar(const AutofillOfferData* offer) {
+    offer_notification_controller_android_->ShowIfNecessary(offer, &card_);
+  }
+
+  void VerifyInfoBarShownCount(int count) {
+    histogram_tester_.ExpectTotalCount(
+        "Autofill.OfferNotificationInfoBarOffer.CardLinkedOffer", count);
+  }
+
+  void VerifyInfoBarResultMetric(
+      AutofillMetrics::OfferNotificationInfoBarResultMetric metric,
+      int count) {
+    histogram_tester_.ExpectBucketCount(
+        "Autofill.OfferNotificationInfoBarResult.CardLinkedOffer", metric,
+        count);
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(OfferNotificationControllerAndroidBrowserTestForInfobar,
                        ShowInfobarAndAccept) {
   GURL offer_url = GetInitialUrl().DeprecatedGetOriginAsURL();
   SetUpOfferDataWithDomains(offer_url);
@@ -181,7 +200,7 @@ IN_PROC_BROWSER_TEST_F(OfferNotificationInfoBarControllerImplBrowserTest,
       1);
 }
 
-IN_PROC_BROWSER_TEST_F(OfferNotificationInfoBarControllerImplBrowserTest,
+IN_PROC_BROWSER_TEST_F(OfferNotificationControllerAndroidBrowserTestForInfobar,
                        ShowInfobarAndClose) {
   GURL offer_url = GetInitialUrl().DeprecatedGetOriginAsURL();
   SetUpOfferDataWithDomains(offer_url);
@@ -202,7 +221,7 @@ IN_PROC_BROWSER_TEST_F(OfferNotificationInfoBarControllerImplBrowserTest,
       1);
 }
 
-IN_PROC_BROWSER_TEST_F(OfferNotificationInfoBarControllerImplBrowserTest,
+IN_PROC_BROWSER_TEST_F(OfferNotificationControllerAndroidBrowserTestForInfobar,
                        CrossTabStatusTracking) {
   GURL offer_url = GetInitialUrl().DeprecatedGetOriginAsURL();
   int64_t id = SetUpOfferDataWithDomains(offer_url)->GetOfferId();
@@ -219,4 +238,64 @@ IN_PROC_BROWSER_TEST_F(OfferNotificationInfoBarControllerImplBrowserTest,
   VerifyInfoBarShownCount(0);
 }
 
+class OfferNotificationControllerAndroidBrowserTestForMessagesUi
+    : public OfferNotificationControllerAndroidBrowserTest {
+ public:
+  OfferNotificationControllerAndroidBrowserTestForMessagesUi() = default;
+
+  void SetUp() override {
+    scoped_feature_list_.InitWithFeatures(
+        /*enabled_features=*/{messages::kMessagesForAndroidInfrastructure,
+                              messages::kMessagesForAndroidOfferNotification},
+        /*disabled_features=*/{});
+    OfferNotificationControllerAndroidBrowserTest::SetUp();
+  }
+
+  void VerifyMessageShownCountMetric(int count) {
+    histogram_tester_.ExpectBucketCount(
+        "Android.Messages.Enqueued.Visible",
+        static_cast<int>(messages::MessageIdentifier::OFFER_NOTIFICATION),
+        count);
+  }
+
+  messages::MessagesTestHelper messages_test_helper_;
+};
+
+IN_PROC_BROWSER_TEST_F(
+    OfferNotificationControllerAndroidBrowserTestForMessagesUi,
+    MessageShown) {
+  GURL offer_url = GetInitialUrl().DeprecatedGetOriginAsURL();
+  SetUpOfferDataWithDomains(offer_url);
+  ASSERT_TRUE(content::NavigateToURL(GetWebContents(), GetInitialUrl()));
+  // Verify that the message was shown and logged.
+  EXPECT_EQ(messages_test_helper_.GetMessageCount(
+                GetWebContents()->GetTopLevelNativeWindow()),
+            1);
+  EXPECT_EQ(
+      messages_test_helper_.GetMessageIdentifier(
+          GetWebContents()->GetTopLevelNativeWindow(), /* enqueue index */ 0),
+      static_cast<int>(messages::MessageIdentifier::OFFER_NOTIFICATION));
+  VerifyMessageShownCountMetric(1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    OfferNotificationControllerAndroidBrowserTestForMessagesUi,
+    CrossTabStatusTracking) {
+  GURL offer_url = GetInitialUrl().DeprecatedGetOriginAsURL();
+  int64_t id = SetUpOfferDataWithDomains(offer_url)->GetOfferId();
+
+  SetShownOffer(id);
+  // Navigate to a different URL within the same domain and try to show the
+  // message.
+  offer_url = embedded_test_server()->GetURL(kHostName, "/simple_page.html");
+  ASSERT_TRUE(content::NavigateToURL(GetWebContents(), offer_url));
+
+  // Verify that the message was not shown again because it has already been
+  // marked as shown for this domain.
+  EXPECT_EQ(messages_test_helper_.GetMessageCount(
+                GetWebContents()->GetTopLevelNativeWindow()),
+            0);
+  VerifyMessageShownCountMetric(0);
+}
+
 }  // namespace autofill
diff --git a/chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.cc b/chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.cc
deleted file mode 100644
index 8b5e15531bd25..0000000000000
--- a/chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.h"
-
-#include "chrome/browser/ui/android/infobars/autofill_offer_notification_infobar.h"
-#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
-#include "components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.h"
-#include "components/infobars/content/content_infobar_manager.h"
-#include "components/infobars/core/infobar.h"
-#include "ui/android/window_android.h"
-
-namespace autofill {
-
-OfferNotificationInfoBarControllerImpl::OfferNotificationInfoBarControllerImpl(
-    content::WebContents* contents)
-    : web_contents_(contents) {}
-
-void OfferNotificationInfoBarControllerImpl::ShowIfNecessary(
-    const AutofillOfferData* offer,
-    const CreditCard* card) {
-  DCHECK(offer);
-  if (!card)
-    return;
-
-  infobars::ContentInfoBarManager::FromWebContents(web_contents_)
-      ->AddInfoBar(std::make_unique<AutofillOfferNotificationInfoBar>(
-          std::make_unique<AutofillOfferNotificationInfoBarDelegateMobile>(
-              offer->GetOfferDetailsUrl(), *card)));
-}
-
-void OfferNotificationInfoBarControllerImpl::Dismiss() {
-  infobars::ContentInfoBarManager* content_infobar_manager =
-      infobars::ContentInfoBarManager::FromWebContents(web_contents_);
-  if (!content_infobar_manager)
-    return;
-
-  for (size_t i = 0; i < content_infobar_manager->infobar_count(); ++i) {
-    infobars::InfoBar* infobar = content_infobar_manager->infobar_at(i);
-    if (infobar->delegate()->GetIdentifier() ==
-        infobars::InfoBarDelegate::
-            AUTOFILL_OFFER_NOTIFICATION_INFOBAR_DELEGATE) {
-      content_infobar_manager->RemoveInfoBar(infobar);
-      return;
-    }
-  }
-}
-
-}  // namespace autofill
diff --git a/chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.h b/chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.h
deleted file mode 100644
index 7b45961b831b5..0000000000000
--- a/chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_OFFER_NOTIFICATION_INFOBAR_CONTROLLER_IMPL_H_
-#define CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_OFFER_NOTIFICATION_INFOBAR_CONTROLLER_IMPL_H_
-
-#include "base/memory/raw_ptr.h"
-#include "components/autofill/core/browser/data_model/credit_card.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_user_data.h"
-
-namespace autofill {
-
-class AutofillOfferData;
-
-// Per-tab controller to control the offer notification infobar displayed on
-// mobile.
-class OfferNotificationInfoBarControllerImpl {
- public:
-  explicit OfferNotificationInfoBarControllerImpl(
-      content::WebContents* contents);
-  ~OfferNotificationInfoBarControllerImpl() = default;
-
-  OfferNotificationInfoBarControllerImpl(
-      const OfferNotificationInfoBarControllerImpl&) = delete;
-  OfferNotificationInfoBarControllerImpl& operator=(
-      const OfferNotificationInfoBarControllerImpl&) = delete;
-
-  // Show the infobar unless it was already shown in the same tab with the same
-  // origin.
-  void ShowIfNecessary(const AutofillOfferData* offer, const CreditCard* card);
-
-  // Dismiss the infobar if it is visible.
-  void Dismiss();
-
- private:
-  raw_ptr<content::WebContents> web_contents_;
-};
-
-}  // namespace autofill
-
-#endif  // CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_OFFER_NOTIFICATION_INFOBAR_CONTROLLER_IMPL_H_
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index f8455544b6ca7..bc88312a4b42d 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -853,7 +853,7 @@ if (is_android) {
       "../browser/ssl/crlset_browsertest.cc",
       "../browser/subresource_filter/subresource_filter_browser_test_harness.cc",
       "../browser/subresource_filter/subresource_filter_browser_test_harness.h",
-      "../browser/ui/autofill/payments/offer_notification_infobar_controller_impl_browsertest.cc",
+      "../browser/ui/autofill/payments/offer_notification_controller_android_browsertest.cc",
       "../browser/ui/webui/policy/policy_ui_browsertest.cc",
       "../renderer/autofill/fake_mojo_password_manager_driver.cc",
       "../renderer/autofill/fake_mojo_password_manager_driver.h",
diff --git a/components/autofill/core/browser/payments/autofill_offer_manager.h b/components/autofill/core/browser/payments/autofill_offer_manager.h
index 1a49cc4e21f64..a444c6ec6a876 100644
--- a/components/autofill/core/browser/payments/autofill_offer_manager.h
+++ b/components/autofill/core/browser/payments/autofill_offer_manager.h
@@ -78,7 +78,7 @@ class AutofillOfferManager : public KeyedService,
       CreateCardLinkedOffersMap_ReturnsOnlyCardLinkedOffers);
   FRIEND_TEST_ALL_PREFIXES(AutofillOfferManagerTest, IsUrlEligible);
   friend class OfferNotificationBubbleViewsInteractiveUiTest;
-  friend class OfferNotificationInfoBarControllerImplBrowserTest;
+  friend class OfferNotificationControllerAndroidBrowserTest;
 
   // Queries |personal_data_| to reset the elements of
   // |eligible_merchant_domains_|
diff --git a/components/autofill_payments_strings.grdp b/components/autofill_payments_strings.grdp
index c14e8b157f589..b0d811e81d6ab 100644
--- a/components/autofill_payments_strings.grdp
+++ b/components/autofill_payments_strings.grdp
@@ -671,12 +671,21 @@
     </message>
   </if>
   <if expr="is_android">
-    <message name="IDS_AUTOFILL_OFFERS_REMINDER_DESCRIPTION_TEXT" desc="Secondary explanatory text for the Clank infobar shown on the merchant website when an offer is available to use." formatter_data="android_java">
+    <message name="IDS_AUTOFILL_OFFERS_REMINDER_DESCRIPTION_TEXT" desc="Secondary explanatory text for the infobar shown on the merchant website when an offer is available to use." formatter_data="android_java">
       Pay with <ph name="CARD_DETAIL">%1$s<ex>Visa - 1234</ex></ph> at checkout.
     </message>
     <message name="IDS_AUTOFILL_OFFERS_REMINDER_DEEP_LINK_TEXT" desc="Text to be linked to take the user to the offer in the Google Pay app." formatter_data="android_java">
       See details
     </message>
+    <message name="IDS_AUTOFILL_OFFERS_MESSAGE_TITLE" desc="Title of the message shown on the merchant website when a GPay-activated card linked offer is available to use.">
+      Google Pay offer available
+    </message>
+    <message name="IDS_AUTOFILL_OFFERS_MESSAGE_DESCRIPTION_TEXT" desc="Secondary explanatory text for the message shown on the merchant website when an offer is available to use.">
+      Check out with <ph name="CARD_DETAIL">$1<ex>Visa - 1234</ex></ph> to use offer
+    </message>
+    <message name="IDS_AUTOFILL_OFFERS_MESSAGE_PRIMARY_BUTTON_TEXT" desc="Text for the primary button of the message shown on the merchant website when a GPay-activated card linked offer is available to use.">
+      Details
+    </message>
   </if>
   <if expr="toolkit_views">
     <message name="IDS_AUTOFILL_PROMO_CODE_OFFERS_REMINDER_TITLE" desc="Title of the bubble shown on the merchant website when a merchant promo code offer is available to use.">
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_OFFERS_MESSAGE_DESCRIPTION_TEXT.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_OFFERS_MESSAGE_DESCRIPTION_TEXT.png.sha1
new file mode 100644
index 0000000000000..bbbd9c4502a3f
--- /dev/null
+++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_OFFERS_MESSAGE_DESCRIPTION_TEXT.png.sha1
@@ -0,0 +1 @@
+587b54e3577dbb3f64e126b4d7c01c4480bac10e
\ No newline at end of file
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_OFFERS_MESSAGE_PRIMARY_BUTTON_TEXT.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_OFFERS_MESSAGE_PRIMARY_BUTTON_TEXT.png.sha1
new file mode 100644
index 0000000000000..3072d2f3e4ea4
--- /dev/null
+++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_OFFERS_MESSAGE_PRIMARY_BUTTON_TEXT.png.sha1
@@ -0,0 +1 @@
+33628376178104d1b7a0adddac1e4bd96995e208
\ No newline at end of file
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_OFFERS_MESSAGE_TITLE.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_OFFERS_MESSAGE_TITLE.png.sha1
new file mode 100644
index 0000000000000..4a9273aae5935
--- /dev/null
+++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_OFFERS_MESSAGE_TITLE.png.sha1
@@ -0,0 +1 @@
+1f41b89f1889a8e89497daf7d63ac16bf0113bd2
\ No newline at end of file