[Fullscreen Control] Fixing the touch behavior

* Fix the issue of |input_entry_method_| not being reset to NOT_ACTIVE
  when the popup is hidden.
* Use ET_GESTURE_LONG_PRESS instead of ET_GESTURE_LONG_TAP so that
  animation is triggered before the tap is released.
* Add auto timeout to the popup when it is triggered by touch.
* Hide the popup when it is triggered by touch and the user touches
  outside of the popup.

Bug: 758456
Change-Id: Id2cb6642a4e9129a096c5025d5695aeacf304717
Reviewed-on: https://chromium-review.googlesource.com/775734
Reviewed-by: Robert Liao <robliao@chromium.org>
Commit-Queue: Yuwei Huang <yuweih@chromium.org>
Cr-Commit-Position: refs/heads/master@{#517256}
diff --git a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.cc b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.cc
index a01f68d2..94fda584 100644
--- a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.cc
+++ b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.cc
@@ -37,46 +37,28 @@
 // +----------------------------+
 constexpr float kShowFullscreenExitControlHeight = 3.f;
 
+// Time to wait to hide the popup when it is triggered by touch input.
+constexpr int kTouchPopupTimeoutMs = 3000;
+
 }  // namespace
 
 FullscreenControlHost::FullscreenControlHost(BrowserView* browser_view,
                                              views::View* host_view)
     : browser_view_(browser_view),
-      fullscreen_control_popup_(browser_view->GetBubbleParentView(),
-                                base::Bind(&BrowserView::ExitFullscreen,
-                                           base::Unretained(browser_view))) {}
+      fullscreen_control_popup_(
+          browser_view->GetBubbleParentView(),
+          base::Bind(&BrowserView::ExitFullscreen,
+                     base::Unretained(browser_view)),
+          base::Bind(&FullscreenControlHost::OnVisibilityChanged,
+                     base::Unretained(this))) {}
 
 FullscreenControlHost::~FullscreenControlHost() = default;
 
 void FullscreenControlHost::OnMouseEvent(ui::MouseEvent* event) {
-  if (event->type() == ui::ET_MOUSE_MOVED)
-    HandleFullScreenControlVisibility(event, InputEntryMethod::MOUSE);
-}
-
-void FullscreenControlHost::OnTouchEvent(ui::TouchEvent* event) {
-  if (event->type() == ui::ET_TOUCH_MOVED)
-    HandleFullScreenControlVisibility(event, InputEntryMethod::TOUCH);
-}
-
-void FullscreenControlHost::OnGestureEvent(ui::GestureEvent* event) {
-  if (event->type() == ui::ET_GESTURE_LONG_TAP)
-    HandleFullScreenControlVisibility(event, InputEntryMethod::TOUCH);
-}
-
-void FullscreenControlHost::Hide(bool animate) {
-  fullscreen_control_popup_.Hide(animate);
-}
-
-bool FullscreenControlHost::IsVisible() const {
-  return fullscreen_control_popup_.IsVisible();
-}
-
-void FullscreenControlHost::HandleFullScreenControlVisibility(
-    const ui::LocatedEvent* event,
-    InputEntryMethod input_entry_method) {
-  if (fullscreen_control_popup_.IsAnimating() ||
+  if (event->type() != ui::ET_MOUSE_MOVED ||
+      fullscreen_control_popup_.IsAnimating() ||
       (input_entry_method_ != InputEntryMethod::NOT_ACTIVE &&
-       input_entry_method_ != input_entry_method)) {
+       input_entry_method_ != InputEntryMethod::MOUSE)) {
     return;
   }
 
@@ -88,16 +70,43 @@
       if (event->y() >= y_limit)
         Hide(true);
     } else {
-      if (event->y() <= kShowFullscreenExitControlHeight ||
-          event->type() == ui::ET_GESTURE_LONG_TAP) {
-        ShowForInputEntryMethod(input_entry_method);
-      }
+      if (event->y() <= kShowFullscreenExitControlHeight)
+        ShowForInputEntryMethod(InputEntryMethod::MOUSE);
     }
   } else if (IsVisible()) {
     Hide(true);
   }
 }
 
+void FullscreenControlHost::OnTouchEvent(ui::TouchEvent* event) {
+  // Hide the popup if the popup is showing and the user touches outside of the
+  // popup.
+  if (event->type() == ui::ET_TOUCH_PRESSED && IsVisible() &&
+      !fullscreen_control_popup_.IsAnimating() &&
+      input_entry_method_ == InputEntryMethod::TOUCH) {
+    Hide(true);
+  }
+}
+
+void FullscreenControlHost::OnGestureEvent(ui::GestureEvent* event) {
+  if (event->type() == ui::ET_GESTURE_LONG_PRESS &&
+      browser_view_->IsFullscreen() && !IsVisible()) {
+    ShowForInputEntryMethod(InputEntryMethod::TOUCH);
+    touch_timeout_timer_.Start(
+        FROM_HERE, base::TimeDelta::FromMilliseconds(kTouchPopupTimeoutMs),
+        base::Bind(&FullscreenControlHost::OnTouchPopupTimeout,
+                   base::Unretained(this)));
+  }
+}
+
+void FullscreenControlHost::Hide(bool animate) {
+  fullscreen_control_popup_.Hide(animate);
+}
+
+bool FullscreenControlHost::IsVisible() const {
+  return fullscreen_control_popup_.IsVisible();
+}
+
 void FullscreenControlHost::ShowForInputEntryMethod(
     InputEntryMethod input_entry_method) {
   input_entry_method_ = input_entry_method;
@@ -106,3 +115,15 @@
     bubble->HideImmediately();
   fullscreen_control_popup_.Show(browser_view_->GetClientAreaBoundsInScreen());
 }
+
+void FullscreenControlHost::OnVisibilityChanged() {
+  if (!IsVisible())
+    input_entry_method_ = InputEntryMethod::NOT_ACTIVE;
+}
+
+void FullscreenControlHost::OnTouchPopupTimeout() {
+  if (IsVisible() && !fullscreen_control_popup_.IsAnimating() &&
+      input_entry_method_ == InputEntryMethod::TOUCH) {
+    Hide(true);
+  }
+}
diff --git a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.h b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.h
index 9368aba..9778193 100644
--- a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.h
+++ b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_VIEWS_FULLSCREEN_CONTROL_FULLSCREEN_CONTROL_HOST_H_
 
 #include "base/macros.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/views/fullscreen_control/fullscreen_control_popup.h"
 #include "ui/events/event_handler.h"
 
@@ -13,7 +14,6 @@
 class FullscreenControlView;
 
 namespace ui {
-class LocatedEvent;
 class GestureEvent;
 class MouseEvent;
 class TouchEvent;
@@ -52,15 +52,16 @@
     TOUCH,       // A touch event caused the view to show.
   };
 
-  void HandleFullScreenControlVisibility(const ui::LocatedEvent* event,
-                                         InputEntryMethod input_entry_method);
   void ShowForInputEntryMethod(InputEntryMethod input_entry_method);
+  void OnVisibilityChanged();
+  void OnTouchPopupTimeout();
 
   InputEntryMethod input_entry_method_ = InputEntryMethod::NOT_ACTIVE;
 
   BrowserView* const browser_view_;
 
   FullscreenControlPopup fullscreen_control_popup_;
+  base::OneShotTimer touch_timeout_timer_;
 
   DISALLOW_COPY_AND_ASSIGN(FullscreenControlHost);
 };
diff --git a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_popup.cc b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_popup.cc
index 16e4d14a..c1fb9d5a 100644
--- a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_popup.cc
+++ b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_popup.cc
@@ -39,10 +39,13 @@
 
 FullscreenControlPopup::FullscreenControlPopup(
     gfx::NativeView parent_view,
-    const base::RepeatingClosure& on_button_pressed)
+    const base::RepeatingClosure& on_button_pressed,
+    const base::RepeatingClosure& on_visibility_changed)
     : control_view_(new FullscreenControlView(on_button_pressed)),
       popup_(CreatePopupWidget(parent_view, control_view_)),
-      animation_(std::make_unique<gfx::SlideAnimation>(this)) {
+      animation_(std::make_unique<gfx::SlideAnimation>(this)),
+      on_visibility_changed_(on_visibility_changed) {
+  DCHECK(on_visibility_changed_);
   animation_->Reset(0);
 }
 
@@ -61,6 +64,8 @@
   // to prevent potential flickering.
   AnimationProgressed(animation_.get());
   popup_->Show();
+
+  OnVisibilityChanged();
 }
 
 void FullscreenControlPopup::Hide(bool animated) {
@@ -113,6 +118,7 @@
     // It's the end of the reversed animation. Just hide the popup in this case.
     parent_bounds_in_screen_ = gfx::Rect();
     popup_->Hide();
+    OnVisibilityChanged();
     return;
   }
   AnimationProgressed(animation);
@@ -127,3 +133,7 @@
                     parent_bounds_in_screen_.y() + y_offset);
   return {origin, control_view_->GetPreferredSize()};
 }
+
+void FullscreenControlPopup::OnVisibilityChanged() {
+  on_visibility_changed_.Run();
+}
diff --git a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_popup.h b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_popup.h
index b1e1c8c..9973087 100644
--- a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_popup.h
+++ b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_popup.h
@@ -7,7 +7,7 @@
 
 #include <memory>
 
-#include "base/callback_forward.h"
+#include "base/callback.h"
 #include "base/macros.h"
 #include "ui/gfx/animation/animation_delegate.h"
 #include "ui/gfx/animation/slide_animation.h"
@@ -25,7 +25,8 @@
 class FullscreenControlPopup : public gfx::AnimationDelegate {
  public:
   FullscreenControlPopup(gfx::NativeView parent_view,
-                         const base::RepeatingClosure& on_button_pressed);
+                         const base::RepeatingClosure& on_button_pressed,
+                         const base::RepeatingClosure& on_visibility_changed);
   ~FullscreenControlPopup() override;
 
   // Shows the indicator with an animation that drops it off the top of
@@ -61,6 +62,8 @@
 
   gfx::Rect CalculateBounds(int y_offset) const;
 
+  void OnVisibilityChanged();
+
   FullscreenControlView* const control_view_;
   const std::unique_ptr<views::Widget> popup_;
   const std::unique_ptr<gfx::SlideAnimation> animation_;
@@ -68,6 +71,8 @@
   // The bounds is empty when the popup is not showing.
   gfx::Rect parent_bounds_in_screen_;
 
+  const base::RepeatingClosure on_visibility_changed_;
+
   DISALLOW_COPY_AND_ASSIGN(FullscreenControlPopup);
 };
 
diff --git a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_popup_unittest.cc b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_popup_unittest.cc
index b4dc15f2..9ccb7c8 100644
--- a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_popup_unittest.cc
+++ b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_popup_unittest.cc
@@ -29,7 +29,8 @@
     parent_widget_->SetBounds(gfx::Rect(100, 100, 640, 480));
     parent_widget_->Show();
     popup_ = std::make_unique<FullscreenControlPopup>(
-        parent_widget_->GetNativeView(), base::BindRepeating(&base::DoNothing));
+        parent_widget_->GetNativeView(), base::BindRepeating(&base::DoNothing),
+        base::BindRepeating(&base::DoNothing));
     animation_api_ = std::make_unique<gfx::AnimationTestApi>(
         popup_->GetAnimationForTesting());
   }