1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef CHROMEOS_UI_FRAME_IMMERSIVE_IMMERSIVE_FULLSCREEN_CONTROLLER_H_
6 #define CHROMEOS_UI_FRAME_IMMERSIVE_IMMERSIVE_FULLSCREEN_CONTROLLER_H_
7 
8 #include <memory>
9 #include <vector>
10 
11 #include "base/component_export.h"
12 #include "base/macros.h"
13 #include "base/timer/timer.h"
14 #include "chromeos/ui/frame/immersive/immersive_revealed_lock.h"
15 #include "ui/aura/window_observer.h"
16 #include "ui/events/event_handler.h"
17 #include "ui/events/event_observer.h"
18 #include "ui/gfx/animation/animation_delegate.h"
19 #include "ui/gfx/animation/slide_animation.h"
20 #include "ui/views/view_observer.h"
21 #include "ui/views/widget/widget_observer.h"
22 
23 namespace aura {
24 class WindowTargeter;
25 }  // namespace aura
26 
27 namespace ash {
28 class ImmersiveFullscreenControllerTest;
29 }  // namespace ash
30 
31 namespace gfx {
32 class Point;
33 }  // namespace gfx
34 
35 namespace ui {
36 class GestureEvent;
37 class LocatedEvent;
38 class MouseEvent;
39 class TouchEvent;
40 }  // namespace ui
41 
42 namespace views {
43 class View;
44 class Widget;
45 }  // namespace views
46 
47 namespace chromeos {
48 
49 class ImmersiveFocusWatcher;
50 class ImmersiveFullscreenControllerDelegate;
51 class ImmersiveFullscreenControllerTestApi;
52 
53 // This class is tested as part of //ash, eg ImmersiveFullscreenControllerTest,
54 // which inherits from AshTestBase.
COMPONENT_EXPORT(CHROMEOS_UI_FRAME)55 class COMPONENT_EXPORT(CHROMEOS_UI_FRAME) ImmersiveFullscreenController
56     : public aura::WindowObserver,
57       public gfx::AnimationDelegate,
58       public ui::EventObserver,
59       public ui::EventHandler,
60       public views::ViewObserver,
61       public ImmersiveRevealedLock::Delegate {
62  public:
63   // How many pixels are reserved for touch-events towards the top of an
64   // immersive-fullscreen window.
65   static const int kImmersiveFullscreenTopEdgeInset;
66 
67   // The height in pixels of the region below the top edge of the display in
68   // which the mouse can trigger revealing the top-of-window views. The height
69   // must be greater than 1px because the top pixel is used to trigger moving
70   // the cursor between displays if the user has a vertical display layout
71   // (primary display above/below secondary display).
72   static const int kMouseRevealBoundsHeight;
73 
74   ImmersiveFullscreenController();
75   ~ImmersiveFullscreenController() override;
76 
77   // Initializes the controller. Must be called prior to enabling immersive
78   // fullscreen via EnableForWidget(). |top_container| is used to keep the
79   // top-of-window views revealed when a child of |top_container| has focus.
80   // |top_container| does not affect which mouse and touch events keep the
81   // top-of-window views revealed. |widget| is the widget to make fullscreen.
82   void Init(ImmersiveFullscreenControllerDelegate* delegate,
83             views::Widget* widget,
84             views::View* top_container);
85 
86   // Returns true if in immersive fullscreen.
87   bool IsEnabled() const;
88 
89   // Returns true if in immersive fullscreen and the top-of-window views are
90   // fully or partially visible.
91   bool IsRevealed() const;
92 
93   // Returns a lock which will keep the top-of-window views revealed for its
94   // lifetime. Several locks can be obtained. When all of the locks are
95   // destroyed, if immersive fullscreen is enabled and there is nothing else
96   // keeping the top-of-window views revealed, the top-of-window views will be
97   // closed. This method always returns a valid lock regardless of whether
98   // immersive fullscreen is enabled. The lock's lifetime can span immersive
99   // fullscreen being enabled / disabled. If acquiring the lock causes a reveal,
100   // the top-of-window views will animate according to |animate_reveal|. The
101   // caller takes ownership of the returned lock.
102   ImmersiveRevealedLock* GetRevealedLock(AnimateReveal animate_reveal)
103       WARN_UNUSED_RESULT;
104 
105   views::Widget* widget() { return widget_; }
106   views::View* top_container() { return top_container_; }
107 
108   // ui::EventObserver:
109   void OnEvent(const ui::Event& event) override;
110 
111   // ui::EventHandler:
112   void OnEvent(ui::Event* event) override;
113   void OnGestureEvent(ui::GestureEvent* event) override;
114 
115   // aura::WindowObserver:
116   void OnWindowPropertyChanged(aura::Window* window,
117                                const void* key,
118                                intptr_t old) override;
119   void OnWindowDestroying(aura::Window* window) override;
120 
121   // views::ViewObserver:
122   void OnViewBoundsChanged(views::View* observed_view) override;
123   void OnViewIsDeleting(views::View* observed_view) override;
124 
125   // gfx::AnimationDelegate overrides:
126   void AnimationEnded(const gfx::Animation* animation) override;
127   void AnimationProgressed(const gfx::Animation* animation) override;
128 
129   // chromeos::ImmersiveRevealedLock::Delegate overrides:
130   void LockRevealedState(AnimateReveal animate_reveal) override;
131   void UnlockRevealedState() override;
132 
133   static void EnableForWidget(views::Widget* widget, bool enabled);
134 
135   static ImmersiveFullscreenController* Get(views::Widget* widget);
136 
137  private:
138   friend class ash::ImmersiveFullscreenControllerTest;
139   friend class ImmersiveFullscreenControllerTestApi;
140 
141   enum Animate {
142     ANIMATE_NO,
143     ANIMATE_SLOW,
144     ANIMATE_FAST,
145   };
146   enum RevealState {
147     CLOSED,
148     SLIDING_OPEN,
149     REVEALED,
150     SLIDING_CLOSED,
151   };
152   enum SwipeType { SWIPE_OPEN, SWIPE_CLOSE, SWIPE_NONE };
153 
154   // Enables or disables observers for the widget's aura::Window and
155   // |top_container_|.
156   void EnableWindowObservers(bool enable);
157 
158   // Enables or disables observers for mouse, touch, focus, and activation.
159   void EnableEventObservers(bool enable);
160 
161   // Called to handle EventObserver::OnEvent.
162   void HandleMouseEvent(const ui::MouseEvent& event,
163                         const gfx::Point& location_in_screen,
164                         views::Widget* target);
165   void HandleTouchEvent(const ui::TouchEvent& event,
166                         const gfx::Point& location_in_screen);
167 
168   // Updates |top_edge_hover_timer_| based on a mouse |event|. If the mouse is
169   // hovered at the top of the screen the timer is started. If the mouse moves
170   // away from the top edge, or moves too much in the x direction, the timer is
171   // stopped.
172   void UpdateTopEdgeHoverTimer(const ui::MouseEvent& event,
173                                const gfx::Point& location_in_screen,
174                                views::Widget* target);
175 
176   // Updates |located_event_revealed_lock_| based on the current mouse state and
177   // the current touch state.
178   // |event| is null if the source event is not known.
179   void UpdateLocatedEventRevealedLock(const ui::LocatedEvent* event,
180                                       const gfx::Point& location_in_screen);
181 
182   // Convenience for calling two argument version with a null event and looking
183   // up the location from the last mouse location.
184   void UpdateLocatedEventRevealedLock();
185 
186   // Acquires |located_event_revealed_lock_| if it is not already held.
187   void AcquireLocatedEventRevealedLock();
188 
189   // Updates |focus_revealed_lock_| based on the currently active view and the
190   // currently active widget.
191   void UpdateFocusRevealedLock();
192 
193   // Update |located_event_revealed_lock_| and |focus_revealed_lock_| as a
194   // result of a gesture of |swipe_type|. Returns true if any locks were
195   // acquired or released.
196   bool UpdateRevealedLocksForSwipe(SwipeType swipe_type);
197 
198   // Returns the animation duration given |animate|.
199   base::TimeDelta GetAnimationDuration(Animate animate) const;
200 
201   // Temporarily reveals the top-of-window views while in immersive mode,
202   // hiding them when the cursor exits the area of the top views. If |animate|
203   // is not ANIMATE_NO, slides in the view, otherwise shows it immediately.
204   void MaybeStartReveal(Animate animate);
205 
206   // Called when the animation to slide open the top-of-window views has
207   // completed.
208   void OnSlideOpenAnimationCompleted();
209 
210   // Hides the top-of-window views if immersive mode is enabled and nothing is
211   // keeping them revealed. Optionally animates.
212   void MaybeEndReveal(Animate animate);
213 
214   // Called when the animation to slide out the top-of-window views has
215   // completed.
216   void OnSlideClosedAnimationCompleted();
217 
218   // Returns the type of swipe given |event|.
219   SwipeType GetSwipeType(const ui::GestureEvent& event) const;
220 
221   // Returns true if a mouse event at |location_in_screen| should be ignored.
222   // Ignored mouse events should not contribute to revealing or unrevealing the
223   // top-of-window views.
224   bool ShouldIgnoreMouseEventAtLocation(
225       const gfx::Point& location_in_screen) const;
226 
227   // True when |location| is "near" to the top container. When the top container
228   // is not closed "near" means within the displayed bounds or above it. When
229   // the top container is closed "near" means either within the displayed
230   // bounds, above it, or within a few pixels below it. This allow the container
231   // to steal enough pixels to detect a swipe in and handles the case that there
232   // is a bezel sensor above the top container.
233   bool ShouldHandleGestureEvent(const gfx::Point& location) const;
234 
235   // Returns the display bounds of the screen |widget_| is on.
236   gfx::Rect GetDisplayBoundsInScreen() const;
237 
238   // Test if the |widget| is the event target to control reveal state.
239   bool IsTargetForWidget(views::Widget* widget) const;
240 
241   // Enables or disables immersive fullscreen in accordance with the
242   // kImmersiveIsActive property.
243   void UpdateEnabled();
244 
245   // Adds insets that redirect touch events at the top of the Widget to the
246   // Widget's window instead of a child window. These insets allow triggering
247   // immersive reveal and are not used when the immersive reveal is already
248   // active.
249   void EnableTouchInsets(bool enable);
250 
251   // Not owned.
252   ImmersiveFullscreenControllerDelegate* delegate_ = nullptr;
253   views::View* top_container_ = nullptr;
254   views::Widget* widget_ = nullptr;
255 
256   // True if the observers have been enabled.
257   bool event_observers_enabled_ = false;
258 
259   // True when in immersive fullscreen.
260   bool enabled_ = false;
261 
262   // State machine for the revealed/closed animations.
263   RevealState reveal_state_ = CLOSED;
264 
265   int revealed_lock_count_ = 0;
266 
267   // Timer to track cursor being held at the top edge of the screen.
268   base::OneShotTimer top_edge_hover_timer_;
269 
270   // The cursor x position in screen coordinates when the cursor first hit the
271   // top edge of the screen.
272   int mouse_x_when_hit_top_in_screen_ = -1;
273 
274   // Tracks if the controller has seen a ET_GESTURE_SCROLL_BEGIN, without the
275   // following events.
276   bool gesture_begun_ = false;
277 
278   // Lock which keeps the top-of-window views revealed based on the current
279   // mouse state and the current touch state. Acquiring the lock is used to
280   // trigger a reveal when the user moves the mouse to the top of the screen
281   // and when the user does a SWIPE_OPEN edge gesture.
282   std::unique_ptr<ImmersiveRevealedLock> located_event_revealed_lock_;
283 
284   std::unique_ptr<gfx::AnimationDelegate> animation_notifier_;
285 
286   // The animation which controls sliding the top-of-window views in and out.
287   std::unique_ptr<gfx::SlideAnimation> animation_;
288 
289   // Whether the animations are disabled for testing.
290   bool animations_disabled_for_test_;
291 
292   std::unique_ptr<ImmersiveFocusWatcher> immersive_focus_watcher_;
293 
294   // The window targeter that was in use before immersive fullscreen mode was
295   // entered, if any. Will be re-installed on the window after leaving immersive
296   // fullscreen.
297   std::unique_ptr<aura::WindowTargeter> normal_targeter_;
298 
299   // |animations_disabled_for_test_| is initialized to this. See
300   // ImmersiveFullscreenControllerTestApi::GlobalAnimationDisabler for details.
301   static bool value_for_animations_disabled_for_test_;
302 
303   base::WeakPtrFactory<ImmersiveFullscreenController> weak_ptr_factory_{this};
304 
305   DISALLOW_COPY_AND_ASSIGN(ImmersiveFullscreenController);
306 };
307 
308 }  // namespace chromeos
309 
310 #endif  // CHROMEOS_UI_FRAME_IMMERSIVE_IMMERSIVE_FULLSCREEN_CONTROLLER_H_
311