blob: 4f0b20b23315e5b4e95cf87e2735ff727d290804 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <vector>
#include "ash/ash_export.h"
#include "ash/wm/immersive_revealed_lock.h"
#include "base/timer/timer.h"
#include "ui/aura/window_observer.h"
#include "ui/events/event_handler.h"
#include "ui/gfx/animation/animation_delegate.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/widget/widget_observer.h"
#include "ui/wm/core/transient_window_observer.h"
namespace aura {
class Window;
namespace gfx {
class Point;
class Rect;
class SlideAnimation;
namespace ui {
class LocatedEvent;
namespace views {
class View;
class Widget;
namespace ash {
class ASH_EXPORT ImmersiveFullscreenController
: public gfx::AnimationDelegate,
public ui::EventHandler,
public ::wm::TransientWindowObserver,
public views::FocusChangeListener,
public views::WidgetObserver,
public ImmersiveRevealedLock::Delegate {
static const int kMouseRevealBoundsHeight;
// The enum is used for an enumerated histogram. New items should be only
// added to the end.
enum WindowType {
class Delegate {
// Called when a reveal of the top-of-window views starts.
virtual void OnImmersiveRevealStarted() = 0;
// Called when the top-of-window views have finished closing. This call
// implies a visible fraction of 0. SetVisibleFraction(0) may not be called
// prior to OnImmersiveRevealEnded().
virtual void OnImmersiveRevealEnded() = 0;
// Called as a result of disabling immersive fullscreen via SetEnabled().
virtual void OnImmersiveFullscreenExited() = 0;
// Called to update the fraction of the top-of-window views height which is
// visible.
virtual void SetVisibleFraction(double visible_fraction) = 0;
// Returns a list of rects whose union makes up the top-of-window views.
// The returned list is used for hittesting when the top-of-window views
// are revealed. GetVisibleBoundsInScreen() must return a valid value when
// not in immersive fullscreen for the sake of SetupForTest().
virtual std::vector<gfx::Rect> GetVisibleBoundsInScreen() const = 0;
virtual ~Delegate() {}
virtual ~ImmersiveFullscreenController();
// Initializes the controller. Must be called prior to enabling immersive
// fullscreen via SetEnabled(). |top_container| is used to keep the
// top-of-window views revealed when a child of |top_container| has focus.
// |top_container| does not affect which mouse and touch events keep the
// top-of-window views revealed.
void Init(Delegate* delegate,
views::Widget* widget,
views::View* top_container);
// Enables or disables immersive fullscreen.
// |window_type| is the type of window which is put in immersive fullscreen.
// It is only used for histogramming.
void SetEnabled(WindowType window_type, bool enable);
// Returns true if |native_window_| is in immersive fullscreen.
bool IsEnabled() const;
// Returns true if |native_window_| is in immersive fullscreen and the
// top-of-window views are fully or partially visible.
bool IsRevealed() const;
// Returns a lock which will keep the top-of-window views revealed for its
// lifetime. Several locks can be obtained. When all of the locks are
// destroyed, if immersive fullscreen is enabled and there is nothing else
// keeping the top-of-window views revealed, the top-of-window views will be
// closed. This method always returns a valid lock regardless of whether
// immersive fullscreen is enabled. The lock's lifetime can span immersive
// fullscreen being enabled / disabled. If acquiring the lock causes a reveal,
// the top-of-window views will animate according to |animate_reveal|. The
// caller takes ownership of the returned lock.
ImmersiveRevealedLock* GetRevealedLock(
AnimateReveal animate_reveal) WARN_UNUSED_RESULT;
// Disables animations and moves the mouse so that it is not over the
// top-of-window views for the sake of testing.
void SetupForTest();
// ui::EventHandler overrides:
virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
// views::FocusChangeObserver overrides:
virtual void OnWillChangeFocus(views::View* focused_before,
views::View* focused_now) OVERRIDE;
virtual void OnDidChangeFocus(views::View* focused_before,
views::View* focused_now) OVERRIDE;
// views::WidgetObserver overrides:
virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE;
virtual void OnWidgetActivationChanged(views::Widget* widget,
bool active) OVERRIDE;
// gfx::AnimationDelegate overrides:
virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE;
virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE;
// ::wm::TransientWindowObserver overrides:
virtual void OnTransientChildAdded(aura::Window* window,
aura::Window* transient) OVERRIDE;
virtual void OnTransientChildRemoved(aura::Window* window,
aura::Window* transient) OVERRIDE;
// ash::ImmersiveRevealedLock::Delegate overrides:
virtual void LockRevealedState(AnimateReveal animate_reveal) OVERRIDE;
virtual void UnlockRevealedState() OVERRIDE;
friend class ImmersiveFullscreenControllerTest;
enum Animate {
enum RevealState {
enum SwipeType {
// Enables or disables observers for mouse, touch, focus, and activation.
void EnableWindowObservers(bool enable);
// Updates |top_edge_hover_timer_| based on a mouse |event|. If the mouse is
// hovered at the top of the screen the timer is started. If the mouse moves
// away from the top edge, or moves too much in the x direction, the timer is
// stopped.
void UpdateTopEdgeHoverTimer(ui::MouseEvent* event);
// Updates |located_event_revealed_lock_| based on the current mouse state and
// the current touch state.
// |event| is NULL if the source event is not known.
void UpdateLocatedEventRevealedLock(ui::LocatedEvent* event);
// Acquires |located_event_revealed_lock_| if it is not already held.
void AcquireLocatedEventRevealedLock();
// Updates |focus_revealed_lock_| based on the currently active view and the
// currently active widget.
void UpdateFocusRevealedLock();
// Update |located_event_revealed_lock_| and |focus_revealed_lock_| as a
// result of a gesture of |swipe_type|. Returns true if any locks were
// acquired or released.
bool UpdateRevealedLocksForSwipe(SwipeType swipe_type);
// Returns the animation duration given |animate|.
int GetAnimationDuration(Animate animate) const;
// Temporarily reveals the top-of-window views while in immersive mode,
// hiding them when the cursor exits the area of the top views. If |animate|
// is not ANIMATE_NO, slides in the view, otherwise shows it immediately.
void MaybeStartReveal(Animate animate);
// Called when the animation to slide open the top-of-window views has
// completed.
void OnSlideOpenAnimationCompleted();
// Hides the top-of-window views if immersive mode is enabled and nothing is
// keeping them revealed. Optionally animates.
void MaybeEndReveal(Animate animate);
// Called when the animation to slide out the top-of-window views has
// completed.
void OnSlideClosedAnimationCompleted();
// Returns the type of swipe given |event|.
SwipeType GetSwipeType(ui::GestureEvent* event) const;
// Returns true if a mouse event at |location_in_screen| should be ignored.
// Ignored mouse events should not contribute to revealing or unrevealing the
// top-of-window views.
bool ShouldIgnoreMouseEventAtLocation(
const gfx::Point& location_in_screen) const;
// True when |location| is "near" to the top container. When the top container
// is not closed "near" means within the displayed bounds or above it. When
// the top container is closed "near" means either within the displayed
// bounds, above it, or within a few pixels below it. This allow the container
// to steal enough pixels to detect a swipe in and handles the case that there
// is a bezel sensor above the top container.
bool ShouldHandleGestureEvent(const gfx::Point& location) const;
// Recreate |bubble_manager_| and start observing any bubbles anchored to a
// child of |top_container_|.
void RecreateBubbleManager();
// Not owned.
Delegate* delegate_;
views::View* top_container_;
views::Widget* widget_;
aura::Window* native_window_;
// True if the observers have been enabled.
bool observers_enabled_;
// True when in immersive fullscreen.
bool enabled_;
// State machine for the revealed/closed animations.
RevealState reveal_state_;
int revealed_lock_count_;
// Timer to track cursor being held at the top edge of the screen.
base::OneShotTimer<ImmersiveFullscreenController> top_edge_hover_timer_;
// The cursor x position in screen coordinates when the cursor first hit the
// top edge of the screen.
int mouse_x_when_hit_top_in_screen_;
// Tracks if the controller has seen a ET_GESTURE_SCROLL_BEGIN, without the
// following events.
bool gesture_begun_;
// Lock which keeps the top-of-window views revealed based on the current
// mouse state and the current touch state. Acquiring the lock is used to
// trigger a reveal when the user moves the mouse to the top of the screen
// and when the user does a SWIPE_OPEN edge gesture.
scoped_ptr<ImmersiveRevealedLock> located_event_revealed_lock_;
// Lock which keeps the top-of-window views revealed based on the focused view
// and the active widget. Acquiring the lock never triggers a reveal because
// a view is not focusable till a reveal has made it visible.
scoped_ptr<ImmersiveRevealedLock> focus_revealed_lock_;
// The animation which controls sliding the top-of-window views in and out.
scoped_ptr<gfx::SlideAnimation> animation_;
// Whether the animations are disabled for testing.
bool animations_disabled_for_test_;
// Manages bubbles which are anchored to a child of |top_container_|.
class BubbleManager;
scoped_ptr<BubbleManager> bubble_manager_;
base::WeakPtrFactory<ImmersiveFullscreenController> weak_ptr_factory_;
} // namespace ash