Show credit card error icon when some cards save fails, instead of
showing the same card icon.

Bug: 917288
Change-Id: I869e5edc3f668afbcc0f5309839ab37317336eac
Reviewed-on: https://chromium-review.googlesource.com/c/1385451
Commit-Queue: Jason Guo <jiahuiguo@chromium.org>
Reviewed-by: Evan Stade <estade@chromium.org>
Cr-Commit-Position: refs/heads/master@{#622214}
diff --git a/chrome/browser/ui/autofill/manage_migration_ui_controller.cc b/chrome/browser/ui/autofill/manage_migration_ui_controller.cc
index 78ac301..aa6b1e9 100644
--- a/chrome/browser/ui/autofill/manage_migration_ui_controller.cc
+++ b/chrome/browser/ui/autofill/manage_migration_ui_controller.cc
@@ -55,6 +55,16 @@
 
   DCHECK_EQ(flow_step_, LocalCardMigrationFlowStep::MIGRATION_RESULT_PENDING);
   flow_step_ = LocalCardMigrationFlowStep::MIGRATION_FINISHED;
+  for (const auto& cc : migratable_credit_cards) {
+    if (cc.migration_status() ==
+        MigratableCreditCard::MigrationStatus::FAILURE_ON_UPLOAD) {
+      flow_step_ = LocalCardMigrationFlowStep::MIGRATION_FAILED;
+      break;
+    }
+  }
+  if (has_server_error)
+    flow_step_ = LocalCardMigrationFlowStep::MIGRATION_FAILED;
+
   // Show error dialog when |has_server_error| is true, which indicates
   // Payments Rpc failure.
   show_error_dialog_ = has_server_error;
@@ -70,6 +80,10 @@
       break;
     }
     case LocalCardMigrationFlowStep::MIGRATION_FINISHED: {
+      ShowFeedbackDialog();
+      break;
+    }
+    case LocalCardMigrationFlowStep::MIGRATION_FAILED: {
       show_error_dialog_ ? ShowErrorDialog() : ShowFeedbackDialog();
       break;
     }
diff --git a/chrome/browser/ui/autofill/manage_migration_ui_controller.h b/chrome/browser/ui/autofill/manage_migration_ui_controller.h
index 1f4e3b0..bdcef7f 100644
--- a/chrome/browser/ui/autofill/manage_migration_ui_controller.h
+++ b/chrome/browser/ui/autofill/manage_migration_ui_controller.h
@@ -32,6 +32,9 @@
   // Migration is finished. Should show the credit card icon when migration
   // is finished and the feedback dialog is ready.
   MIGRATION_FINISHED,
+  // Migration is finished and there are some cards save fails, or payments
+  // server error.
+  MIGRATION_FAILED,
   // Should show the feedback dialog containing the migration results of cards
   // that the user selected to upload after the user clicking the credit card
   // icon.
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_icon_view.cc b/chrome/browser/ui/views/autofill/local_card_migration_icon_view.cc
index 7de1455..a358d9d 100644
--- a/chrome/browser/ui/views/autofill/local_card_migration_icon_view.cc
+++ b/chrome/browser/ui/views/autofill/local_card_migration_icon_view.cc
@@ -15,6 +15,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/paint_vector_icon.h"
 
 namespace autofill {
 
@@ -72,6 +73,7 @@
       // to be manually set since the migration dialog is not anchored at the
       // credit card icon.
       case LocalCardMigrationFlowStep::OFFER_DIALOG: {
+        UpdateIconImage();
         AnimateInkDrop(views::InkDropState::ACTIVATED, /*event=*/nullptr);
         break;
       }
@@ -88,6 +90,11 @@
         SetEnabled(true);
         break;
       }
+      case LocalCardMigrationFlowStep::MIGRATION_FAILED: {
+        UnpauseAnimation();
+        SetEnabled(true);
+        break;
+      }
       default:
         break;
     }
@@ -108,6 +115,15 @@
   return kCreditCardIcon;
 }
 
+const gfx::VectorIcon& LocalCardMigrationIconView::GetVectorIconBadge() const {
+  ManageMigrationUiController* controller = GetController();
+  if (controller && controller->GetFlowStep() ==
+                        LocalCardMigrationFlowStep::MIGRATION_FAILED) {
+    return kBlockedBadgeIcon;
+  }
+  return gfx::kNoneIcon;
+}
+
 base::string16 LocalCardMigrationIconView::GetTextForTooltipAndAccessibleName()
     const {
   return l10n_util::GetStringUTF16(IDS_TOOLTIP_MIGRATE_LOCAL_CARD);
@@ -146,4 +162,10 @@
   }
 }
 
+void LocalCardMigrationIconView::AnimationEnded(
+    const gfx::Animation* animation) {
+  IconLabelBubbleView::AnimationEnded(animation);
+  UpdateIconImage();
+}
+
 }  // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_icon_view.h b/chrome/browser/ui/views/autofill/local_card_migration_icon_view.h
index 669007b..2dea42b 100644
--- a/chrome/browser/ui/views/autofill/local_card_migration_icon_view.h
+++ b/chrome/browser/ui/views/autofill/local_card_migration_icon_view.h
@@ -37,12 +37,14 @@
   // PageActionIconView:
   void OnExecuting(PageActionIconView::ExecuteSource execute_source) override;
   const gfx::VectorIcon& GetVectorIcon() const override;
+  const gfx::VectorIcon& GetVectorIconBadge() const override;
 
  private:
   ManageMigrationUiController* GetController() const;
 
   // IconLabelBubbleView:
   void AnimationProgressed(const gfx::Animation* animation) override;
+  void AnimationEnded(const gfx::Animation* animation) override;
 
   // Used to do nullptr check when getting the controller.
   Browser* const browser_;
diff --git a/chrome/browser/ui/views/page_action/page_action_icon_view.cc b/chrome/browser/ui/views/page_action/page_action_icon_view.cc
index c2bb86c..cf60c44a 100644
--- a/chrome/browser/ui/views/page_action/page_action_icon_view.cc
+++ b/chrome/browser/ui/views/page_action/page_action_icon_view.cc
@@ -221,6 +221,10 @@
     command_updater_->ExecuteCommand(command_id_);
 }
 
+const gfx::VectorIcon& PageActionIconView::GetVectorIconBadge() const {
+  return gfx::kNoneIcon;
+}
+
 void PageActionIconView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
   views::BubbleDialogDelegateView* bubble = GetBubble();
   if (bubble)
@@ -250,7 +254,8 @@
                            ? theme->GetSystemColor(
                                  ui::NativeTheme::kColorId_ProminentButtonColor)
                            : icon_color_;
-  SetImage(gfx::CreateVectorIcon(GetVectorIcon(), icon_size_, icon_color));
+  SetImage(gfx::CreateVectorIconWithBadge(GetVectorIcon(), icon_size_,
+                                          icon_color, GetVectorIconBadge()));
 }
 
 void PageActionIconView::SetActiveInternal(bool active) {
diff --git a/chrome/browser/ui/views/page_action/page_action_icon_view.h b/chrome/browser/ui/views/page_action/page_action_icon_view.h
index cdc7318..4cedcd7 100644
--- a/chrome/browser/ui/views/page_action/page_action_icon_view.h
+++ b/chrome/browser/ui/views/page_action/page_action_icon_view.h
@@ -118,16 +118,19 @@
   // Calls OnExecuting and runs |command_id_| with a valid |command_updater_|.
   virtual void ExecuteCommand(ExecuteSource source);
 
-  // Gets the given vector icon in the correct color and size based on |active|.
+  // Gets the given vector icon.
   virtual const gfx::VectorIcon& GetVectorIcon() const = 0;
 
+  // Provides the badge to be shown on top of the vector icon, if any.
+  virtual const gfx::VectorIcon& GetVectorIconBadge() const;
+
   // IconLabelBubbleView:
   void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
   void OnTouchUiChanged() override;
   void UpdateBorder() override;
 
   // Updates the icon image after some state has changed.
-  void UpdateIconImage();
+  virtual void UpdateIconImage();
 
   // Sets the active state of the icon. An active icon will be displayed in a
   // "call to action" color.