Torne (Richard Coles) | f2477e0 | 2013-11-28 11:55:43 +0000 | [diff] [blame] | 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 ASH_WM_IMMERSIVE_FULLSCREEN_CONTROLLER_H_ |
| 6 | #define ASH_WM_IMMERSIVE_FULLSCREEN_CONTROLLER_H_ |
| 7 | |
| 8 | #include <vector> |
| 9 | |
| 10 | #include "ash/ash_export.h" |
| 11 | #include "ash/wm/immersive_revealed_lock.h" |
| 12 | #include "base/timer/timer.h" |
| 13 | #include "ui/aura/window_observer.h" |
| 14 | #include "ui/events/event_handler.h" |
| 15 | #include "ui/gfx/animation/animation_delegate.h" |
| 16 | #include "ui/views/focus/focus_manager.h" |
| 17 | #include "ui/views/widget/widget_observer.h" |
Torne (Richard Coles) | a140131 | 2014-03-18 10:20:56 +0000 | [diff] [blame] | 18 | #include "ui/wm/core/transient_window_observer.h" |
Torne (Richard Coles) | f2477e0 | 2013-11-28 11:55:43 +0000 | [diff] [blame] | 19 | |
| 20 | namespace aura { |
| 21 | class Window; |
| 22 | } |
| 23 | |
| 24 | namespace gfx { |
| 25 | class Point; |
| 26 | class Rect; |
| 27 | class SlideAnimation; |
| 28 | } |
| 29 | |
| 30 | namespace ui { |
| 31 | class LocatedEvent; |
| 32 | } |
| 33 | |
| 34 | namespace views { |
| 35 | class View; |
| 36 | class Widget; |
| 37 | } |
| 38 | |
| 39 | namespace ash { |
| 40 | |
| 41 | class ASH_EXPORT ImmersiveFullscreenController |
| 42 | : public gfx::AnimationDelegate, |
| 43 | public ui::EventHandler, |
Torne (Richard Coles) | a140131 | 2014-03-18 10:20:56 +0000 | [diff] [blame] | 44 | public ::wm::TransientWindowObserver, |
Torne (Richard Coles) | f2477e0 | 2013-11-28 11:55:43 +0000 | [diff] [blame] | 45 | public views::FocusChangeListener, |
| 46 | public views::WidgetObserver, |
Torne (Richard Coles) | f2477e0 | 2013-11-28 11:55:43 +0000 | [diff] [blame] | 47 | public ImmersiveRevealedLock::Delegate { |
| 48 | public: |
Ben Murdoch | a02191e | 2014-04-16 11:17:03 +0100 | [diff] [blame] | 49 | static const int kMouseRevealBoundsHeight; |
| 50 | |
Torne (Richard Coles) | 5d1f7b1 | 2014-02-21 12:16:55 +0000 | [diff] [blame] | 51 | // The enum is used for an enumerated histogram. New items should be only |
| 52 | // added to the end. |
| 53 | enum WindowType { |
| 54 | WINDOW_TYPE_OTHER, |
| 55 | WINDOW_TYPE_BROWSER, |
| 56 | WINDOW_TYPE_HOSTED_APP, |
| 57 | WINDOW_TYPE_PACKAGED_APP, |
| 58 | WINDOW_TYPE_COUNT |
| 59 | }; |
| 60 | |
Torne (Richard Coles) | f2477e0 | 2013-11-28 11:55:43 +0000 | [diff] [blame] | 61 | class Delegate { |
| 62 | public: |
| 63 | // Called when a reveal of the top-of-window views starts. |
| 64 | virtual void OnImmersiveRevealStarted() = 0; |
| 65 | |
| 66 | // Called when the top-of-window views have finished closing. This call |
| 67 | // implies a visible fraction of 0. SetVisibleFraction(0) may not be called |
| 68 | // prior to OnImmersiveRevealEnded(). |
| 69 | virtual void OnImmersiveRevealEnded() = 0; |
| 70 | |
| 71 | // Called as a result of disabling immersive fullscreen via SetEnabled(). |
| 72 | virtual void OnImmersiveFullscreenExited() = 0; |
| 73 | |
| 74 | // Called to update the fraction of the top-of-window views height which is |
| 75 | // visible. |
| 76 | virtual void SetVisibleFraction(double visible_fraction) = 0; |
| 77 | |
| 78 | // Returns a list of rects whose union makes up the top-of-window views. |
| 79 | // The returned list is used for hittesting when the top-of-window views |
| 80 | // are revealed. GetVisibleBoundsInScreen() must return a valid value when |
| 81 | // not in immersive fullscreen for the sake of SetupForTest(). |
| 82 | virtual std::vector<gfx::Rect> GetVisibleBoundsInScreen() const = 0; |
| 83 | |
| 84 | protected: |
| 85 | virtual ~Delegate() {} |
| 86 | }; |
| 87 | |
| 88 | ImmersiveFullscreenController(); |
| 89 | virtual ~ImmersiveFullscreenController(); |
| 90 | |
| 91 | // Initializes the controller. Must be called prior to enabling immersive |
| 92 | // fullscreen via SetEnabled(). |top_container| is used to keep the |
| 93 | // top-of-window views revealed when a child of |top_container| has focus. |
| 94 | // |top_container| does not affect which mouse and touch events keep the |
| 95 | // top-of-window views revealed. |
| 96 | void Init(Delegate* delegate, |
| 97 | views::Widget* widget, |
| 98 | views::View* top_container); |
| 99 | |
| 100 | // Enables or disables immersive fullscreen. |
Torne (Richard Coles) | 5d1f7b1 | 2014-02-21 12:16:55 +0000 | [diff] [blame] | 101 | // |window_type| is the type of window which is put in immersive fullscreen. |
| 102 | // It is only used for histogramming. |
| 103 | void SetEnabled(WindowType window_type, bool enable); |
Torne (Richard Coles) | f2477e0 | 2013-11-28 11:55:43 +0000 | [diff] [blame] | 104 | |
| 105 | // Returns true if |native_window_| is in immersive fullscreen. |
| 106 | bool IsEnabled() const; |
| 107 | |
| 108 | // Returns true if |native_window_| is in immersive fullscreen and the |
| 109 | // top-of-window views are fully or partially visible. |
| 110 | bool IsRevealed() const; |
| 111 | |
| 112 | // Returns a lock which will keep the top-of-window views revealed for its |
| 113 | // lifetime. Several locks can be obtained. When all of the locks are |
| 114 | // destroyed, if immersive fullscreen is enabled and there is nothing else |
| 115 | // keeping the top-of-window views revealed, the top-of-window views will be |
| 116 | // closed. This method always returns a valid lock regardless of whether |
| 117 | // immersive fullscreen is enabled. The lock's lifetime can span immersive |
| 118 | // fullscreen being enabled / disabled. If acquiring the lock causes a reveal, |
| 119 | // the top-of-window views will animate according to |animate_reveal|. The |
| 120 | // caller takes ownership of the returned lock. |
| 121 | ImmersiveRevealedLock* GetRevealedLock( |
| 122 | AnimateReveal animate_reveal) WARN_UNUSED_RESULT; |
| 123 | |
| 124 | // Disables animations and moves the mouse so that it is not over the |
| 125 | // top-of-window views for the sake of testing. |
| 126 | void SetupForTest(); |
| 127 | |
| 128 | // ui::EventHandler overrides: |
| 129 | virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE; |
| 130 | virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE; |
| 131 | virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE; |
| 132 | |
| 133 | // views::FocusChangeObserver overrides: |
| 134 | virtual void OnWillChangeFocus(views::View* focused_before, |
| 135 | views::View* focused_now) OVERRIDE; |
| 136 | virtual void OnDidChangeFocus(views::View* focused_before, |
| 137 | views::View* focused_now) OVERRIDE; |
| 138 | |
| 139 | // views::WidgetObserver overrides: |
| 140 | virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE; |
| 141 | virtual void OnWidgetActivationChanged(views::Widget* widget, |
| 142 | bool active) OVERRIDE; |
| 143 | |
| 144 | // gfx::AnimationDelegate overrides: |
| 145 | virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE; |
| 146 | virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE; |
| 147 | |
Torne (Richard Coles) | a140131 | 2014-03-18 10:20:56 +0000 | [diff] [blame] | 148 | // ::wm::TransientWindowObserver overrides: |
Torne (Richard Coles) | 5d1f7b1 | 2014-02-21 12:16:55 +0000 | [diff] [blame] | 149 | virtual void OnTransientChildAdded(aura::Window* window, |
| 150 | aura::Window* transient) OVERRIDE; |
| 151 | virtual void OnTransientChildRemoved(aura::Window* window, |
| 152 | aura::Window* transient) OVERRIDE; |
Torne (Richard Coles) | f2477e0 | 2013-11-28 11:55:43 +0000 | [diff] [blame] | 153 | |
| 154 | // ash::ImmersiveRevealedLock::Delegate overrides: |
| 155 | virtual void LockRevealedState(AnimateReveal animate_reveal) OVERRIDE; |
| 156 | virtual void UnlockRevealedState() OVERRIDE; |
| 157 | |
| 158 | private: |
| 159 | friend class ImmersiveFullscreenControllerTest; |
| 160 | |
Torne (Richard Coles) | f2477e0 | 2013-11-28 11:55:43 +0000 | [diff] [blame] | 161 | enum Animate { |
| 162 | ANIMATE_NO, |
| 163 | ANIMATE_SLOW, |
| 164 | ANIMATE_FAST, |
| 165 | }; |
| 166 | enum RevealState { |
| 167 | CLOSED, |
| 168 | SLIDING_OPEN, |
| 169 | REVEALED, |
| 170 | SLIDING_CLOSED, |
| 171 | }; |
| 172 | enum SwipeType { |
| 173 | SWIPE_OPEN, |
| 174 | SWIPE_CLOSE, |
| 175 | SWIPE_NONE |
| 176 | }; |
| 177 | |
| 178 | // Enables or disables observers for mouse, touch, focus, and activation. |
| 179 | void EnableWindowObservers(bool enable); |
| 180 | |
| 181 | // Updates |top_edge_hover_timer_| based on a mouse |event|. If the mouse is |
| 182 | // hovered at the top of the screen the timer is started. If the mouse moves |
| 183 | // away from the top edge, or moves too much in the x direction, the timer is |
| 184 | // stopped. |
| 185 | void UpdateTopEdgeHoverTimer(ui::MouseEvent* event); |
| 186 | |
| 187 | // Updates |located_event_revealed_lock_| based on the current mouse state and |
| 188 | // the current touch state. |
| 189 | // |event| is NULL if the source event is not known. |
Torne (Richard Coles) | a3f6a49 | 2013-12-18 16:25:09 +0000 | [diff] [blame] | 190 | void UpdateLocatedEventRevealedLock(ui::LocatedEvent* event); |
Torne (Richard Coles) | f2477e0 | 2013-11-28 11:55:43 +0000 | [diff] [blame] | 191 | |
| 192 | // Acquires |located_event_revealed_lock_| if it is not already held. |
| 193 | void AcquireLocatedEventRevealedLock(); |
| 194 | |
| 195 | // Updates |focus_revealed_lock_| based on the currently active view and the |
| 196 | // currently active widget. |
| 197 | void UpdateFocusRevealedLock(); |
| 198 | |
| 199 | // Update |located_event_revealed_lock_| and |focus_revealed_lock_| as a |
| 200 | // result of a gesture of |swipe_type|. Returns true if any locks were |
| 201 | // acquired or released. |
| 202 | bool UpdateRevealedLocksForSwipe(SwipeType swipe_type); |
| 203 | |
| 204 | // Returns the animation duration given |animate|. |
| 205 | int GetAnimationDuration(Animate animate) const; |
| 206 | |
| 207 | // Temporarily reveals the top-of-window views while in immersive mode, |
| 208 | // hiding them when the cursor exits the area of the top views. If |animate| |
| 209 | // is not ANIMATE_NO, slides in the view, otherwise shows it immediately. |
| 210 | void MaybeStartReveal(Animate animate); |
| 211 | |
| 212 | // Called when the animation to slide open the top-of-window views has |
| 213 | // completed. |
| 214 | void OnSlideOpenAnimationCompleted(); |
| 215 | |
| 216 | // Hides the top-of-window views if immersive mode is enabled and nothing is |
| 217 | // keeping them revealed. Optionally animates. |
| 218 | void MaybeEndReveal(Animate animate); |
| 219 | |
| 220 | // Called when the animation to slide out the top-of-window views has |
| 221 | // completed. |
| 222 | void OnSlideClosedAnimationCompleted(); |
| 223 | |
| 224 | // Returns the type of swipe given |event|. |
| 225 | SwipeType GetSwipeType(ui::GestureEvent* event) const; |
| 226 | |
| 227 | // Returns true if a mouse event at |location_in_screen| should be ignored. |
| 228 | // Ignored mouse events should not contribute to revealing or unrevealing the |
| 229 | // top-of-window views. |
| 230 | bool ShouldIgnoreMouseEventAtLocation( |
| 231 | const gfx::Point& location_in_screen) const; |
| 232 | |
| 233 | // True when |location| is "near" to the top container. When the top container |
| 234 | // is not closed "near" means within the displayed bounds or above it. When |
| 235 | // the top container is closed "near" means either within the displayed |
| 236 | // bounds, above it, or within a few pixels below it. This allow the container |
| 237 | // to steal enough pixels to detect a swipe in and handles the case that there |
| 238 | // is a bezel sensor above the top container. |
| 239 | bool ShouldHandleGestureEvent(const gfx::Point& location) const; |
| 240 | |
| 241 | // Recreate |bubble_manager_| and start observing any bubbles anchored to a |
| 242 | // child of |top_container_|. |
| 243 | void RecreateBubbleManager(); |
| 244 | |
| 245 | // Not owned. |
| 246 | Delegate* delegate_; |
| 247 | views::View* top_container_; |
| 248 | views::Widget* widget_; |
| 249 | aura::Window* native_window_; |
| 250 | |
| 251 | // True if the observers have been enabled. |
| 252 | bool observers_enabled_; |
| 253 | |
| 254 | // True when in immersive fullscreen. |
| 255 | bool enabled_; |
| 256 | |
| 257 | // State machine for the revealed/closed animations. |
| 258 | RevealState reveal_state_; |
| 259 | |
| 260 | int revealed_lock_count_; |
| 261 | |
| 262 | // Timer to track cursor being held at the top edge of the screen. |
| 263 | base::OneShotTimer<ImmersiveFullscreenController> top_edge_hover_timer_; |
| 264 | |
| 265 | // The cursor x position in screen coordinates when the cursor first hit the |
| 266 | // top edge of the screen. |
| 267 | int mouse_x_when_hit_top_in_screen_; |
| 268 | |
| 269 | // Tracks if the controller has seen a ET_GESTURE_SCROLL_BEGIN, without the |
| 270 | // following events. |
| 271 | bool gesture_begun_; |
| 272 | |
| 273 | // Lock which keeps the top-of-window views revealed based on the current |
| 274 | // mouse state and the current touch state. Acquiring the lock is used to |
| 275 | // trigger a reveal when the user moves the mouse to the top of the screen |
| 276 | // and when the user does a SWIPE_OPEN edge gesture. |
| 277 | scoped_ptr<ImmersiveRevealedLock> located_event_revealed_lock_; |
| 278 | |
| 279 | // Lock which keeps the top-of-window views revealed based on the focused view |
| 280 | // and the active widget. Acquiring the lock never triggers a reveal because |
| 281 | // a view is not focusable till a reveal has made it visible. |
| 282 | scoped_ptr<ImmersiveRevealedLock> focus_revealed_lock_; |
| 283 | |
| 284 | // The animation which controls sliding the top-of-window views in and out. |
| 285 | scoped_ptr<gfx::SlideAnimation> animation_; |
| 286 | |
| 287 | // Whether the animations are disabled for testing. |
| 288 | bool animations_disabled_for_test_; |
| 289 | |
| 290 | // Manages bubbles which are anchored to a child of |top_container_|. |
| 291 | class BubbleManager; |
| 292 | scoped_ptr<BubbleManager> bubble_manager_; |
| 293 | |
| 294 | base::WeakPtrFactory<ImmersiveFullscreenController> weak_ptr_factory_; |
| 295 | |
| 296 | DISALLOW_COPY_AND_ASSIGN(ImmersiveFullscreenController); |
| 297 | }; |
| 298 | |
| 299 | } // namespace ash |
| 300 | |
| 301 | #endif // ASH_WM_IMMERSIVE_FULLSCREEN_CONTROLLER_H_ |