Passwords: Add 3-button save dialog initial metrics

This builds on crrev.com/c/6483569 with:

- A new CLICKED_NOT_NOW dialog dismissal reason
- Interactive test coverage for the new (and existing) dismiss buttons

Bug: 411441552

Change-Id: I0fdc142083710d6be873b7f80da351a83489884b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6501099
Reviewed-by: Dana Fried <dfried@chromium.org>
Reviewed-by: Xinghui Lu <xinghuilu@chromium.org>
Reviewed-by: Maria Kazinova <kazinova@google.com>
Commit-Queue: Christopher Grant <cjgrant@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1456323}
diff --git a/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller.cc b/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller.cc
index 754cb4d1..47021c5 100644
--- a/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller.cc
+++ b/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller.cc
@@ -154,7 +154,7 @@
 
 void SaveUpdateBubbleController::OnNotNowClicked() {
   CHECK_EQ(password_manager::ui::PENDING_PASSWORD_STATE, GetState());
-  // TODO(crbug.com/414573697): Log appropriate metrics.
+  SetDismissalReason(metrics_util::CLICKED_NOT_NOW);
   if (delegate_) {
     delegate_->OnNotNowClicked();
   }
diff --git a/chrome/browser/ui/passwords/manage_passwords_test.h b/chrome/browser/ui/passwords/manage_passwords_test.h
index 49e6f4d4..a4d53cf 100644
--- a/chrome/browser/ui/passwords/manage_passwords_test.h
+++ b/chrome/browser/ui/passwords/manage_passwords_test.h
@@ -105,6 +105,14 @@
       password_manager::PasswordStoreInterface* profile_store = nullptr,
       password_manager::PasswordStoreInterface* account_store = nullptr);
 
+  auto CheckHistogramUniqueSample(const std::string& name,
+                                  int sample,
+                                  int expected_count) {
+    return Do([=, this]() {
+      histogram_tester_.ExpectUniqueSample(name, sample, expected_count);
+    });
+  }
+
  private:
   password_manager::PasswordForm password_form_;
   password_manager::PasswordForm insecure_credential_;
diff --git a/chrome/browser/ui/signin/promos/bubble_signin_promo_interactive_uitest.cc b/chrome/browser/ui/signin/promos/bubble_signin_promo_interactive_uitest.cc
index b3f7c5e5..96e3ee9a 100644
--- a/chrome/browser/ui/signin/promos/bubble_signin_promo_interactive_uitest.cc
+++ b/chrome/browser/ui/signin/promos/bubble_signin_promo_interactive_uitest.cc
@@ -238,16 +238,16 @@
   RunTestSequence(
       WaitForEvent(BubbleSignInPromoSignInButtonView::kPromoSignInButton,
                    kBubbleSignInPromoSignInButtonHasCallback),
-      EnsurePresent(PasswordSaveUpdateView::kPasswordBubble),
+      EnsurePresent(PasswordSaveUpdateView::kPasswordBubbleElementId),
       SetOnIncompatibleAction(
           OnIncompatibleAction::kIgnoreAndContinue,
           "Screenshot can only run in pixel_tests on Windows."),
-      Screenshot(PasswordSaveUpdateView::kPasswordBubble, std::string(),
-                 "5455375"),
+      Screenshot(PasswordSaveUpdateView::kPasswordBubbleElementId,
+                 std::string(), "5455375"),
       NameChildViewByType<views::MdTextButton>(
           BubbleSignInPromoSignInButtonView::kPromoSignInButton, kButton),
       PressButton(kButton).SetMustRemainVisible(false),
-      EnsureNotPresent(PasswordSaveUpdateView::kPasswordBubble));
+      EnsureNotPresent(PasswordSaveUpdateView::kPasswordBubbleElementId));
 
   // Check that clicking the sign in button navigated to a sign in page.
   EXPECT_TRUE(IsSignInURL());
@@ -322,16 +322,16 @@
   RunTestSequence(
       WaitForEvent(BubbleSignInPromoSignInButtonView::kPromoSignInButton,
                    kBubbleSignInPromoSignInButtonHasCallback),
-      EnsurePresent(PasswordSaveUpdateView::kPasswordBubble),
+      EnsurePresent(PasswordSaveUpdateView::kPasswordBubbleElementId),
       SetOnIncompatibleAction(
           OnIncompatibleAction::kIgnoreAndContinue,
           "Screenshot can only run in pixel_tests on Windows."),
-      Screenshot(PasswordSaveUpdateView::kPasswordBubble, std::string(),
-                 "5455375"),
+      Screenshot(PasswordSaveUpdateView::kPasswordBubbleElementId,
+                 std::string(), "5455375"),
       NameChildViewByType<views::MdTextButton>(
           BubbleSignInPromoSignInButtonView::kPromoSignInButton, kButton),
       PressButton(kButton).SetMustRemainVisible(false),
-      EnsureNotPresent(PasswordSaveUpdateView::kPasswordBubble));
+      EnsureNotPresent(PasswordSaveUpdateView::kPasswordBubbleElementId));
 
   // Check that there is no helper attached to the sign in tab, because the
   // password was already moved.
@@ -390,16 +390,16 @@
   RunTestSequence(
       WaitForEvent(BubbleSignInPromoSignInButtonView::kPromoSignInButton,
                    kBubbleSignInPromoSignInButtonHasCallback),
-      EnsurePresent(PasswordSaveUpdateView::kPasswordBubble),
+      EnsurePresent(PasswordSaveUpdateView::kPasswordBubbleElementId),
       SetOnIncompatibleAction(
           OnIncompatibleAction::kIgnoreAndContinue,
           "Screenshot can only run in pixel_tests on Windows."),
-      Screenshot(PasswordSaveUpdateView::kPasswordBubble, std::string(),
-                 "5455375"),
+      Screenshot(PasswordSaveUpdateView::kPasswordBubbleElementId,
+                 std::string(), "5455375"),
       NameChildViewByType<views::MdTextButton>(
           BubbleSignInPromoSignInButtonView::kPromoSignInButton, kButton),
       PressButton(kButton).SetMustRemainVisible(false),
-      EnsureNotPresent(PasswordSaveUpdateView::kPasswordBubble));
+      EnsureNotPresent(PasswordSaveUpdateView::kPasswordBubbleElementId));
 
   // Check that clicking the sign in button navigated to a sign in page.
   EXPECT_TRUE(IsSignInURL());
diff --git a/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc b/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc
index 2139be8..752ff85 100644
--- a/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc
+++ b/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
 #include "chrome/browser/ui/tab_dialogs.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/controls/rich_hover_button.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/passwords/manage_passwords_details_view.h"
@@ -57,6 +58,7 @@
 #include "ui/views/focus/focus_manager.h"
 #include "ui/views/test/views_test_utils.h"
 #include "ui/views/test/widget_test.h"
+#include "ui/views/window/dialog_client_view.h"
 
 using base::Bucket;
 using net::test_server::BasicHttpResponse;
@@ -1342,3 +1344,43 @@
   RunTestSequence(Do(setup_shared_passwords),
                   EnsureNotPresent(SharedPasswordsNotificationView::kTopView));
 }
+
+IN_PROC_BROWSER_TEST_F(PasswordBubbleInteractiveUiTest, ClickNever) {
+  SetupPendingPassword();
+  const auto button = views::DialogClientView::kCancelButtonElementId;
+  RunTestSequence(PressButton(button), WaitForHide(button),
+                  CheckHistogramUniqueSample(
+                      "PasswordManager.SaveUIDismissalReason",
+                      password_manager::metrics_util::CLICKED_NEVER, 1));
+}
+class ThreeButtonPasswordBubbleInteractiveUiTest
+    : public PasswordBubbleInteractiveUiTest {
+ public:
+  ThreeButtonPasswordBubbleInteractiveUiTest() {
+    scoped_feature_list_.InitWithFeatureState(
+        features::kThreeButtonPasswordSaveDialog, true);
+  }
+  ~ThreeButtonPasswordBubbleInteractiveUiTest() override = default;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(ThreeButtonPasswordBubbleInteractiveUiTest,
+                       ClickNotNow) {
+  SetupPendingPassword();
+  const auto button = views::DialogClientView::kCancelButtonElementId;
+  RunTestSequence(PressButton(button), WaitForHide(button),
+                  CheckHistogramUniqueSample(
+                      "PasswordManager.SaveUIDismissalReason",
+                      password_manager::metrics_util::CLICKED_NOT_NOW, 1));
+}
+
+IN_PROC_BROWSER_TEST_F(ThreeButtonPasswordBubbleInteractiveUiTest, ClickNever) {
+  SetupPendingPassword();
+  const auto button = PasswordSaveUpdateView::kExtraButtonElementId;
+  RunTestSequence(PressButton(button), WaitForHide(button),
+                  CheckHistogramUniqueSample(
+                      "PasswordManager.SaveUIDismissalReason",
+                      password_manager::metrics_util::CLICKED_NEVER, 1));
+}
diff --git a/chrome/browser/ui/views/passwords/password_save_update_view.cc b/chrome/browser/ui/views/passwords/password_save_update_view.cc
index 31eb552ff..ad68ce2 100644
--- a/chrome/browser/ui/views/passwords/password_save_update_view.cc
+++ b/chrome/browser/ui/views/passwords/password_save_update_view.cc
@@ -141,6 +141,8 @@
     if (base::FeatureList::IsEnabled(
             features::kThreeButtonPasswordSaveDialog)) {
       extra_view_ = SetExtraView(std::make_unique<views::MdTextButton>());
+      extra_view_->SetProperty(views::kElementIdentifierKey,
+                               kExtraButtonElementId);
     }
   }
 
@@ -241,7 +243,7 @@
   AnnounceBubbleChange();
 
   GetBubbleFrameView()->SetProperty(views::kElementIdentifierKey,
-                                    kPasswordBubble);
+                                    kPasswordBubbleElementId);
 
   return false;
 #else
@@ -442,4 +444,7 @@
 BEGIN_METADATA(PasswordSaveUpdateView)
 END_METADATA
 
-DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(PasswordSaveUpdateView, kPasswordBubble);
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(PasswordSaveUpdateView,
+                                      kPasswordBubbleElementId);
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(PasswordSaveUpdateView,
+                                      kExtraButtonElementId);
diff --git a/chrome/browser/ui/views/passwords/password_save_update_view.h b/chrome/browser/ui/views/passwords/password_save_update_view.h
index 9a1ddfc..ecdcac5 100644
--- a/chrome/browser/ui/views/passwords/password_save_update_view.h
+++ b/chrome/browser/ui/views/passwords/password_save_update_view.h
@@ -28,7 +28,8 @@
   METADATA_HEADER(PasswordSaveUpdateView, PasswordBubbleViewBase)
 
  public:
-  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kPasswordBubble);
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kPasswordBubbleElementId);
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kExtraButtonElementId);
 
   PasswordSaveUpdateView(content::WebContents* web_contents,
                          views::View* anchor_view,
diff --git a/components/password_manager/core/browser/password_form_metrics_recorder.cc b/components/password_manager/core/browser/password_form_metrics_recorder.cc
index 585c881..592825d 100644
--- a/components/password_manager/core/browser/password_form_metrics_recorder.cc
+++ b/components/password_manager/core/browser/password_form_metrics_recorder.cc
@@ -51,6 +51,7 @@
     // Declined by user.
     case metrics_util::CLICKED_CANCEL:
     case metrics_util::CLICKED_NEVER:
+    case metrics_util::CLICKED_NOT_NOW:
       return BubbleDismissalReason::kDeclined;
 
     // Ignored by user.
diff --git a/components/password_manager/core/browser/password_manager_metrics_util.h b/components/password_manager/core/browser/password_manager_metrics_util.h
index 239d93f9..468a32e 100644
--- a/components/password_manager/core/browser/password_manager_metrics_util.h
+++ b/components/password_manager/core/browser/password_manager_metrics_util.h
@@ -67,6 +67,8 @@
 // These values are persisted to logs. Entries should not be renumbered and
 // numeric values should never be reused.
 // Metrics: "PasswordManager.UIDismissalReason"
+//
+// LINT.IfChange(UIDismissalReason)
 enum UIDismissalReason {
   // We use this to mean both "Bubble lost focus" and "No interaction with the
   // infobar".
@@ -86,8 +88,10 @@
   CLICKED_MANAGE_PASSWORD = 13,
   CLICKED_GOT_IT = 14,
   CLICKED_ABOUT_PASSWORD_CHANGE = 15,
+  CLICKED_NOT_NOW = 16,
   NUM_UI_RESPONSES,
 };
+// LINT.ThenChange(/tools/metrics/histograms/metadata/password/enums.xml:PasswordManagerUIDismissalReason)
 
 // Enum representing the different leak detection dialogs shown to the user.
 // Corresponds to LeakDetectionDialogType suffix in histogram_suffixes_list.xml
diff --git a/tools/metrics/histograms/metadata/password/enums.xml b/tools/metrics/histograms/metadata/password/enums.xml
index 79517f2..b15e0fc 100644
--- a/tools/metrics/histograms/metadata/password/enums.xml
+++ b/tools/metrics/histograms/metadata/password/enums.xml
@@ -1338,6 +1338,8 @@
       label="Not Syncing/Sync pasword saved. This value should not happen."/>
 </enum>
 
+<!-- LINT.IfChange(PasswordManagerUIDismissalReason) -->
+
 <enum name="PasswordManagerUIDismissalReason">
   <int value="0" label="Bubble lost focus / No infobar interaction"/>
   <int value="1" label="Clicked 'Save'/'Update'/'Move'/etc"/>
@@ -1360,8 +1362,11 @@
   <int value="15"
       label="Clicked 'About password change' link in the password change
              bubble."/>
+  <int value="16" label="Clicked 'Not now' in the save password bubble."/>
 </enum>
 
+<!-- LINT.ThenChange(/components/password_manager/core/browser/password_manager_metrics_util.h:UIDismissalReason) -->
+
 <enum name="PasswordNoteAction">
   <int value="0"
       label="A new credential is added from settings, with the note field not