[AF][Upstream Feedback] Add new feedback bubble

Mock: https://docs.google.com/presentation/d/130d5_4XAWqI01xt5ejlKw2lohePNQJbxIJQCBK0Kc5k/edit#slide=id.g4d98b81831_2_0

1) Added failure bubble
2) Added new strings used by this new bubble
3) Next three CLs would be adding ChromeAutofillClient logic, adding
experimental logic, and adding unittest/browsertest

Bug: 964127
Change-Id: I4652d6ba55af687afc2d648859c320e1776b2d3e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1616017
Reviewed-by: Evan Stade <estade@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Reviewed-by: Jared Saul <jsaul@google.com>
Commit-Queue: Siyu An <siyua@chromium.org>
Cr-Commit-Position: refs/heads/master@{#661984}
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 1327872..2226cca11 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2478,6 +2478,8 @@
       "views/autofill/payments/payments_view_util.h",
       "views/autofill/payments/save_card_bubble_views.cc",
       "views/autofill/payments/save_card_bubble_views.h",
+      "views/autofill/payments/save_card_failure_bubble_views.cc",
+      "views/autofill/payments/save_card_failure_bubble_views.h",
       "views/autofill/payments/save_card_icon_view.cc",
       "views/autofill/payments/save_card_icon_view.h",
       "views/autofill/payments/save_card_manage_cards_bubble_views.cc",
diff --git a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc
index 9d42da1..bb48f0c 100644
--- a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc
+++ b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc
@@ -163,6 +163,11 @@
   ShowBubble();
 }
 
+void SaveCardBubbleControllerImpl::ShowBubbleForSaveCardFailureForTesting() {
+  current_bubble_type_ = BubbleType::FAILURE;
+  ShowBubble();
+}
+
 void SaveCardBubbleControllerImpl::HideBubble() {
   if (save_card_bubble_view_) {
     save_card_bubble_view_->Hide();
@@ -221,6 +226,8 @@
       return l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_SAVED);
     case BubbleType::MANAGE_CARDS:
       return l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_SAVED);
+    case BubbleType::FAILURE:
+      return l10n_util::GetStringUTF16(IDS_AUTOFILL_FAILURE_BUBBLE_TITLE);
     case BubbleType::INACTIVE:
       NOTREACHED();
       return base::string16();
@@ -228,6 +235,9 @@
 }
 
 base::string16 SaveCardBubbleControllerImpl::GetExplanatoryMessage() const {
+  if (current_bubble_type_ == BubbleType::FAILURE)
+    return l10n_util::GetStringUTF16(IDS_AUTOFILL_FAILURE_BUBBLE_EXPLANATION);
+
   if (current_bubble_type_ != BubbleType::UPLOAD_SAVE)
     return base::string16();
 
@@ -336,6 +346,7 @@
           AutofillMetrics::MANAGE_CARDS_DONE, is_upload_save_);
       return;
     case BubbleType::SIGN_IN_PROMO:
+    case BubbleType::FAILURE:
     case BubbleType::INACTIVE:
       NOTREACHED();
   }
@@ -570,6 +581,9 @@
       break;
     case BubbleType::SIGN_IN_PROMO:
       break;
+    case BubbleType::FAILURE:
+      // TODO(crbug.com/964127): Add metrics.
+      break;
     case BubbleType::INACTIVE:
       NOTREACHED();
   }
@@ -605,6 +619,9 @@
               prefs::kAutofillAcceptSaveCreditCardPromptState),
           GetSecurityLevel(), GetSyncState());
       break;
+    case BubbleType::FAILURE:
+      // TODO(crbug.com/964127): Add metrics.
+      break;
     case BubbleType::MANAGE_CARDS:
     case BubbleType::SIGN_IN_PROMO:
     case BubbleType::INACTIVE:
diff --git a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.h b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.h
index 64072d0..3e2241f 100644
--- a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.h
+++ b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.h
@@ -85,6 +85,10 @@
   // just saved and links the user to manage their other cards.
   void ShowBubbleForManageCardsForTesting(const CreditCard& card);
 
+  // For testing. Sets up the controller for showing the
+  // save card failure bubble.
+  void ShowBubbleForSaveCardFailureForTesting();
+
   void HideBubble();
   void ReshowBubble();
 
diff --git a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_browsertest.cc b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_browsertest.cc
index 54ad16c..ec5a8e9 100644
--- a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_browsertest.cc
+++ b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_browsertest.cc
@@ -78,6 +78,8 @@
       bubble_type = BubbleType::SIGN_IN_PROMO;
     if (name.find("Manage") != std::string::npos)
       bubble_type = BubbleType::MANAGE_CARDS;
+    if (name.find("Failure") != std::string::npos)
+      bubble_type = BubbleType::FAILURE;
 
     switch (bubble_type) {
       case BubbleType::LOCAL_SAVE:
@@ -97,6 +99,9 @@
       case BubbleType::MANAGE_CARDS:
         controller_->ShowBubbleForManageCardsForTesting(test::GetCreditCard());
         break;
+      case BubbleType::FAILURE:
+        controller_->ShowBubbleForSaveCardFailureForTesting();
+        break;
       case BubbleType::INACTIVE:
         break;
     }
@@ -150,6 +155,11 @@
   ShowAndVerifyUi();
 }
 
+// Invokes a bubble displaying the card saving just failed.
+IN_PROC_BROWSER_TEST_F(SaveCardBubbleControllerImplTest, InvokeUi_Failure) {
+  ShowAndVerifyUi();
+}
+
 // Tests that opening a new tab will hide the save card bubble.
 IN_PROC_BROWSER_TEST_F(SaveCardBubbleControllerImplTest, NewTabHidesDialog) {
   ShowUi("Local");
diff --git a/chrome/browser/ui/autofill/payments/save_card_ui.h b/chrome/browser/ui/autofill/payments/save_card_ui.h
index 90d1561..d8f4e58 100644
--- a/chrome/browser/ui/autofill/payments/save_card_ui.h
+++ b/chrome/browser/ui/autofill/payments/save_card_ui.h
@@ -22,6 +22,9 @@
   // icon is clicked.
   MANAGE_CARDS,
 
+  // The failure bubble when credit card uploading failed.
+  FAILURE,
+
   // There is no bubble to show anymore. This also
   // indicates that the icon should not be visible.
   INACTIVE
diff --git a/chrome/browser/ui/views/autofill/payments/save_card_failure_bubble_views.cc b/chrome/browser/ui/views/autofill/payments/save_card_failure_bubble_views.cc
new file mode 100644
index 0000000..e187d3d
--- /dev/null
+++ b/chrome/browser/ui/views/autofill/payments/save_card_failure_bubble_views.cc
@@ -0,0 +1,47 @@
+// Copyright 2019 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/views/autofill/payments/save_card_failure_bubble_views.h"
+
+#include "chrome/browser/ui/views/chrome_layout_provider.h"
+#include "chrome/browser/ui/views/chrome_typography.h"
+#include "components/autofill/core/browser/ui/payments/save_card_bubble_controller.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/layout/box_layout.h"
+
+namespace autofill {
+
+SaveCardFailureBubbleViews::SaveCardFailureBubbleViews(
+    views::View* anchor_view,
+    const gfx::Point& anchor_point,
+    content::WebContents* web_contents,
+    SaveCardBubbleController* controller)
+    : SaveCardBubbleViews(anchor_view, anchor_point, web_contents, controller) {
+}
+
+int SaveCardFailureBubbleViews::GetDialogButtons() const {
+  return ui::DIALOG_BUTTON_NONE;
+}
+
+std::unique_ptr<views::View>
+SaveCardFailureBubbleViews::CreateMainContentView() {
+  std::unique_ptr<views::View> main_view = std::make_unique<views::View>();
+  ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
+
+  main_view->SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::kVertical, gfx::Insets(),
+      provider->GetDistanceMetric(views::DISTANCE_UNRELATED_CONTROL_VERTICAL)));
+
+  base::string16 explanation = controller()->GetExplanatoryMessage();
+  if (!explanation.empty()) {
+    auto* explanation_label = new views::Label(
+        explanation, CONTEXT_BODY_TEXT_LARGE, ChromeTextStyle::STYLE_SECONDARY);
+    explanation_label->SetMultiLine(true);
+    explanation_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+    main_view->AddChildView(explanation_label);
+  }
+  return main_view;
+}
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/payments/save_card_failure_bubble_views.h b/chrome/browser/ui/views/autofill/payments/save_card_failure_bubble_views.h
new file mode 100644
index 0000000..a09faff
--- /dev/null
+++ b/chrome/browser/ui/views/autofill/payments/save_card_failure_bubble_views.h
@@ -0,0 +1,35 @@
+// Copyright 2019 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_VIEWS_AUTOFILL_PAYMENTS_SAVE_CARD_FAILURE_BUBBLE_VIEWS_H_
+#define CHROME_BROWSER_UI_VIEWS_AUTOFILL_PAYMENTS_SAVE_CARD_FAILURE_BUBBLE_VIEWS_H_
+
+#include "chrome/browser/ui/views/autofill/payments/save_card_bubble_views.h"
+
+namespace autofill {
+
+// This class displays the bubble shown when credit card upload failed.
+class SaveCardFailureBubbleViews : public SaveCardBubbleViews {
+ public:
+  SaveCardFailureBubbleViews(views::View* anchor_view,
+                             const gfx::Point& anchor_point,
+                             content::WebContents* web_contents,
+                             SaveCardBubbleController* controller);
+
+  // SaveCardBubbleViews:
+  int GetDialogButtons() const override;
+
+ protected:
+  ~SaveCardFailureBubbleViews() override = default;
+
+ private:
+  // SaveCardBubbleViews:
+  std::unique_ptr<views::View> CreateMainContentView() override;
+
+  DISALLOW_COPY_AND_ASSIGN(SaveCardFailureBubbleViews);
+};
+
+}  // namespace autofill
+
+#endif  // CHROME_BROWSER_UI_VIEWS_AUTOFILL_PAYMENTS_SAVE_CARD_FAILURE_BUBBLE_VIEWS_H_
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 252a06c..c1ef49ee 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -70,6 +70,7 @@
 #include "chrome/browser/ui/views/autofill/payments/local_card_migration_bubble_views.h"
 #include "chrome/browser/ui/views/autofill/payments/local_card_migration_icon_view.h"
 #include "chrome/browser/ui/views/autofill/payments/save_card_bubble_views.h"
+#include "chrome/browser/ui/views/autofill/payments/save_card_failure_bubble_views.h"
 #include "chrome/browser/ui/views/autofill/payments/save_card_icon_view.h"
 #include "chrome/browser/ui/views/autofill/payments/save_card_manage_cards_bubble_views.h"
 #include "chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.h"
@@ -1358,6 +1359,10 @@
       bubble = new autofill::SaveCardManageCardsBubbleViews(
           anchor_view, gfx::Point(), web_contents, controller);
       break;
+    case autofill::BubbleType::FAILURE:
+      bubble = new autofill::SaveCardFailureBubbleViews(
+          anchor_view, gfx::Point(), web_contents, controller);
+      break;
     case autofill::BubbleType::INACTIVE:
       break;
   }
diff --git a/components/autofill_payments_strings.grdp b/components/autofill_payments_strings.grdp
index 8a25aab..e480b07 100644
--- a/components/autofill_payments_strings.grdp
+++ b/components/autofill_payments_strings.grdp
@@ -85,6 +85,12 @@
   <message name="IDS_AUTOFILL_DONE" desc="Text to show for the button in the save card manager bubble when the card has been saved either locally or to Google Payments.">
     Done
   </message>
+  <message name="IDS_AUTOFILL_FAILURE_BUBBLE_TITLE" desc="Title text for the Autofill credit card upload failure bubble.">
+    Can't save card
+  </message>
+  <message name="IDS_AUTOFILL_FAILURE_BUBBLE_EXPLANATION" desc="Explanation text for the Autofill credit card upload failure bubble main content. Shown as user-facing descripion.">
+    Sorry, your card can't be saved right now
+  </message>
   <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION" desc="Explanation of the effect of the Autofill save card prompt when the card is to be saved by uploading it to Google Payments and also saved locally. The prompt can be either a bubble or an infobar.">
     Pay quickly on sites and apps across devices using cards you have saved with Google.
   </message>