Add time based buffer to tab hover card visibility.

This change makes tab hover cards reappear immediately when hovering over a tab if the mouse hover has only been out of the tab strip for 0.5 seconds. This is to prevent wait time when a user unintentionally hovers out of the tab strip while searching for a tab.

Bug: 910739
Change-Id: I47cae3e64fcf86eff12884a3ed63945632d7fd07
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1603054
Commit-Queue: Caroline Rising <corising@chromium.org>
Reviewed-by: Dana Fried <dfried@chromium.org>
Cr-Commit-Position: refs/heads/master@{#659159}
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
index 38fc679..0f8ec8b 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
@@ -140,6 +140,7 @@
         base::TimeDelta::FromMilliseconds(200);
     set_animation_state(FadeAnimationState::FADE_IN);
     widget_->SetOpacity(0);
+    widget_->Show();
     fade_animation_ = std::make_unique<gfx::LinearAnimation>(this);
     fade_animation_->SetDuration(kFadeInDuration);
     fade_animation_->Start();
@@ -329,6 +330,16 @@
 TabHoverCardBubbleView::~TabHoverCardBubbleView() = default;
 
 void TabHoverCardBubbleView::UpdateAndShow(Tab* tab) {
+  // If less than |kShowWithoutDelayTimeBuffer| time has passed since the hover
+  // card was last visible then it is shown immediately. This is to account for
+  // if hover unintentionally leaves the tab strip.
+  constexpr base::TimeDelta kShowWithoutDelayTimeBuffer =
+      base::TimeDelta::FromMilliseconds(500);
+  base::TimeDelta elapsed_time =
+      base::TimeTicks::Now() - last_visible_timestamp_;
+  bool show_immediately = !last_visible_timestamp_.is_null() &&
+                          elapsed_time <= kShowWithoutDelayTimeBuffer;
+
   if (preview_image_)
     preview_image_->SetVisible(!tab->IsActive());
 
@@ -341,18 +352,22 @@
 
   fade_animation_delegate_->CancelFadeOut();
 
-  // Start trigger timer if necessary.
   if (!widget_->IsVisible()) {
-    // Note that this will restart the timer if it is already running. If the
-    // hover cards are not yet visible, moving the cursor within the tabstrip
-    // will not trigger the hover cards.
-    delayed_show_timer_.Start(FROM_HERE, GetDelay(tab->width()), this,
-                              &TabHoverCardBubbleView::FadeInToShow);
+    if (disable_animations_for_testing_ || show_immediately) {
+      widget_->Show();
+    } else {
+      // Note that this will restart the timer if it is already running. If the
+      // hover cards are not yet visible, moving the cursor within the tabstrip
+      // will not trigger the hover cards.
+      delayed_show_timer_.Start(FROM_HERE, GetDelay(tab->width()), this,
+                                &TabHoverCardBubbleView::FadeInToShow);
+    }
   }
 }
 
 void TabHoverCardBubbleView::FadeOutToHide() {
   delayed_show_timer_.Stop();
+  last_visible_timestamp_ = base::TimeTicks::Now();
   if (disable_animations_for_testing_) {
     widget_->Hide();
   } else {
@@ -402,9 +417,7 @@
 }
 
 void TabHoverCardBubbleView::FadeInToShow() {
-  widget_->Show();
-  if (!disable_animations_for_testing_)
-    fade_animation_delegate_->FadeIn();
+  fade_animation_delegate_->FadeIn();
 }
 
 void TabHoverCardBubbleView::UpdateCardContent(TabRendererData data) {
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
index 8df3137..75b38d8 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
@@ -70,6 +70,8 @@
   // Used to animate the tab hover card's movement between tabs.
   std::unique_ptr<WidgetSlideAnimationDelegate> slide_animation_delegate_;
 
+  base::TimeTicks last_visible_timestamp_;
+
   views::Widget* widget_ = nullptr;
   views::Label* title_label_ = nullptr;
   views::Label* domain_label_ = nullptr;