1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// found in the LICENSE file.
4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/wm/immersive_fullscreen_controller.h"
6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
7f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include <set>
8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/ash_constants.h"
10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/shell.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/wm/resize_handle_window_targeter.h"
12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/wm/window_state.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/metrics/histogram.h"
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/aura/client/aura_constants.h"
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/aura/client/capture_client.h"
16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/aura/client/cursor_client.h"
17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/aura/client/screen_position_client.h"
18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/aura/env.h"
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/aura/window.h"
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/aura/window_event_dispatcher.h"
21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/gfx/animation/slide_animation.h"
22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/gfx/display.h"
23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/gfx/point.h"
24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/gfx/rect.h"
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/gfx/screen.h"
26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/views/bubble/bubble_delegate.h"
27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/views/view.h"
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/views/widget/widget.h"
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/wm/core/transient_window_manager.h"
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/wm/core/window_util.h"
31effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "ui/wm/public/activation_client.h"
32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using views::View;
34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace ash {
36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace {
38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Duration for the reveal show/hide slide animation. The slower duration is
40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// used for the initial slide out to give the user more change to see what
41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// happened.
42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int kRevealSlowAnimationDurationMs = 400;
43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int kRevealFastAnimationDurationMs = 200;
44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// The delay in milliseconds between the mouse stopping at the top edge of the
46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// screen and the top-of-window views revealing.
47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int kMouseRevealDelayMs = 200;
48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// The maximum amount of pixels that the cursor can move for the cursor to be
50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// considered "stopped". This allows the user to reveal the top-of-window views
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// without holding the cursor completely still.
52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int kMouseRevealXThresholdPixels = 3;
53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Used to multiply x value of an update in check to determine if gesture is
55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// vertical. This is used to make sure that gesture is close to vertical instead
56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// of just more vertical then horizontal.
57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int kSwipeVerticalThresholdMultiplier = 3;
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// The height in pixels of the region above the top edge of the display which
60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// hosts the immersive fullscreen window in which mouse events are ignored
61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// (cannot reveal or unreveal the top-of-window views).
62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// See ShouldIgnoreMouseEventAtLocation() for more details.
63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int kHeightOfDeadRegionAboveTopContainer = 10;
64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Returns the BubbleDelegateView corresponding to |maybe_bubble| if
66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// |maybe_bubble| is a bubble.
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)views::BubbleDelegateView* AsBubbleDelegate(aura::Window* maybe_bubble) {
68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!maybe_bubble)
69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return NULL;
70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  views::Widget* widget = views::Widget::GetWidgetForNativeView(maybe_bubble);
71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!widget)
72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return NULL;
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return widget->widget_delegate()->AsBubbleDelegate();
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Returns true if |maybe_transient| is a transient child of |toplevel|.
77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool IsWindowTransientChildOf(aura::Window* maybe_transient,
78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                              aura::Window* toplevel) {
79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!maybe_transient || !toplevel)
80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (aura::Window* window = maybe_transient; window;
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       window = ::wm::GetTransientParent(window)) {
84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (window == toplevel)
85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return true;
86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return false;
88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Returns the location of |event| in screen coordinates.
91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)gfx::Point GetEventLocationInScreen(const ui::LocatedEvent& event) {
92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Point location_in_screen = event.location();
93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  aura::Window* target = static_cast<aura::Window*>(event.target());
94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  aura::client::ScreenPositionClient* screen_position_client =
95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      aura::client::GetScreenPositionClient(target->GetRootWindow());
96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  screen_position_client->ConvertPointToScreen(target, &location_in_screen);
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return location_in_screen;
98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Returns the bounds of the display nearest to |window| in screen coordinates.
101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)gfx::Rect GetDisplayBoundsInScreen(aura::Window* window) {
102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return Shell::GetScreen()->GetDisplayNearestWindow(window).bounds();
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}  // namespace
106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
107a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// The height in pixels of the region below the top edge of the display in which
108a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// the mouse can trigger revealing the top-of-window views.
109a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#if defined(OS_WIN)
110a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Windows 8 reserves some pixels at the top of the screen for the hand icon
111a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// that allows you to drag a metro app off the screen, so a few additional
112a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// pixels of space must be reserved for the mouse reveal.
113a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochconst int ImmersiveFullscreenController::kMouseRevealBoundsHeight = 9;
114a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#else
115a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// The height must be greater than 1px because the top pixel is used to trigger
116a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// moving the cursor between displays if the user has a vertical display layout
117a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// (primary display above/below secondary display).
118a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochconst int ImmersiveFullscreenController::kMouseRevealBoundsHeight = 3;
119a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#endif
120a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Class which keeps the top-of-window views revealed as long as one of the
124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// bubbles it is observing is visible. The logic to keep the top-of-window
125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// views revealed based on the visibility of bubbles anchored to
126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// children of |ImmersiveFullscreenController::top_container_| is separate from
127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// the logic related to |ImmersiveFullscreenController::focus_revealed_lock_|
128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// so that bubbles which are not activatable and bubbles which do not close
129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// upon deactivation also keep the top-of-window views revealed for the
130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// duration of their visibility.
131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class ImmersiveFullscreenController::BubbleManager
132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    : public aura::WindowObserver {
133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public:
134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  explicit BubbleManager(ImmersiveFullscreenController* controller);
135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual ~BubbleManager();
136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Start / stop observing changes to |bubble|'s visibility.
138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  void StartObserving(aura::Window* bubble);
139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  void StopObserving(aura::Window* bubble);
140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private:
142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Updates |revealed_lock_| based on whether any of |bubbles_| is visible.
143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  void UpdateRevealedLock();
144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // aura::WindowObserver overrides:
146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual void OnWindowVisibilityChanged(aura::Window* window,
147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                         bool visible) OVERRIDE;
148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ImmersiveFullscreenController* controller_;
151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::set<aura::Window*> bubbles_;
153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Lock which keeps the top-of-window views revealed based on whether any of
155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // |bubbles_| is visible.
156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_ptr<ImmersiveRevealedLock> revealed_lock_;
157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(BubbleManager);
159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)};
160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ImmersiveFullscreenController::BubbleManager::BubbleManager(
162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ImmersiveFullscreenController* controller)
163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    : controller_(controller) {
164f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ImmersiveFullscreenController::BubbleManager::~BubbleManager() {
167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (std::set<aura::Window*>::const_iterator it = bubbles_.begin();
168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)       it != bubbles_.end(); ++it) {
169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    (*it)->RemoveObserver(this);
170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::BubbleManager::StartObserving(
174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    aura::Window* bubble) {
175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (bubbles_.insert(bubble).second) {
176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    bubble->AddObserver(this);
177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    UpdateRevealedLock();
178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::BubbleManager::StopObserving(
182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    aura::Window* bubble) {
183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (bubbles_.erase(bubble)) {
184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    bubble->RemoveObserver(this);
185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    UpdateRevealedLock();
186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::BubbleManager::UpdateRevealedLock() {
190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool has_visible_bubble = false;
191f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (std::set<aura::Window*>::const_iterator it = bubbles_.begin();
192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)       it != bubbles_.end(); ++it) {
193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if ((*it)->IsVisible()) {
194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      has_visible_bubble = true;
195f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      break;
196f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
197f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
199f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool was_revealed = controller_->IsRevealed();
200f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (has_visible_bubble) {
201f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!revealed_lock_.get()) {
202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Reveal the top-of-window views without animating because it looks
203f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // weird for the top-of-window views to animate and the bubble not to
204f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // animate along with the top-of-window views.
205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      revealed_lock_.reset(controller_->GetRevealedLock(
206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
208f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    revealed_lock_.reset();
210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!was_revealed && revealed_lock_.get()) {
213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Currently, there is no nice way for bubbles to reposition themselves
214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // whenever the anchor view moves. Tell the bubbles to reposition themselves
215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // explicitly instead. The hidden bubbles are also repositioned because
216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // BubbleDelegateView does not reposition its widget as a result of a
217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // visibility change.
218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    for (std::set<aura::Window*>::const_iterator it = bubbles_.begin();
219f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)         it != bubbles_.end(); ++it) {
220f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      AsBubbleDelegate(*it)->OnAnchorBoundsChanged();
221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::BubbleManager::OnWindowVisibilityChanged(
226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    aura::Window*,
227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    bool visible) {
228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UpdateRevealedLock();
229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
231f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::BubbleManager::OnWindowDestroying(
232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    aura::Window* window) {
233f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  StopObserving(window);
234f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
235f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
236f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
237f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ImmersiveFullscreenController::ImmersiveFullscreenController()
239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    : delegate_(NULL),
240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      top_container_(NULL),
241f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      widget_(NULL),
242f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      native_window_(NULL),
243f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      observers_enabled_(false),
244f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      enabled_(false),
245f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      reveal_state_(CLOSED),
246f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      revealed_lock_count_(0),
247f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      mouse_x_when_hit_top_in_screen_(-1),
248f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      gesture_begun_(false),
249f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      animation_(new gfx::SlideAnimation(this)),
250f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      animations_disabled_for_test_(false),
251f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      weak_ptr_factory_(this) {
252f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
253f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
254f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ImmersiveFullscreenController::~ImmersiveFullscreenController() {
255f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EnableWindowObservers(false);
256f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
257f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::Init(Delegate* delegate,
259f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                         views::Widget* widget,
260f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                         views::View* top_container) {
261f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  delegate_ = delegate;
262f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  top_container_ = top_container;
263f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  widget_ = widget;
264f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  native_window_ = widget_->GetNativeWindow();
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  native_window_->SetEventTargeter(scoped_ptr<ui::EventTargeter>(
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new ResizeHandleWindowTargeter(native_window_, this)));
267f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
268f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ImmersiveFullscreenController::SetEnabled(WindowType window_type,
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               bool enabled) {
271f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (enabled_ == enabled)
272f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
273f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  enabled_ = enabled;
274f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
275f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EnableWindowObservers(enabled_);
276f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
27746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ash::wm::WindowState* window_state = wm::GetWindowState(native_window_);
278f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Auto hide the shelf in immersive fullscreen instead of hiding it.
27946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  window_state->set_hide_shelf_when_fullscreen(!enabled);
28046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
28146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Update the window's immersive mode state for the window manager.
28246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  window_state->set_in_immersive_fullscreen(enabled);
28346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
284f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  Shell::GetInstance()->UpdateShelfVisibility();
285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
286f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (enabled_) {
287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Animate enabling immersive mode by sliding out the top-of-window views.
288f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // No animation occurs if a lock is holding the top-of-window views open.
289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
290f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Do a reveal to set the initial state for the animation. (And any
291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // required state in case the animation cannot run because of a lock holding
292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // the top-of-window views open.)
293f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    MaybeStartReveal(ANIMATE_NO);
294f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Reset the located event and the focus revealed locks so that they do not
296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // affect whether the top-of-window views are hidden.
297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    located_event_revealed_lock_.reset();
298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    focus_revealed_lock_.reset();
299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Try doing the animation.
301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    MaybeEndReveal(ANIMATE_SLOW);
302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (reveal_state_ == REVEALED) {
304f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Reveal was unsuccessful. Reacquire the revealed locks if appropriate.
305a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      UpdateLocatedEventRevealedLock(NULL);
306f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      UpdateFocusRevealedLock();
307a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else {
308a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // Clearing focus is important because it closes focus-related popups like
309a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // the touch selection handles.
310a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      widget_->GetFocusManager()->ClearFocus();
311f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
312f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
313f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Stop cursor-at-top tracking.
314f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    top_edge_hover_timer_.Stop();
315f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    reveal_state_ = CLOSED;
316f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    delegate_->OnImmersiveFullscreenExited();
318f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (enabled_) {
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION("Ash.ImmersiveFullscreen.WindowType",
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              window_type,
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              WINDOW_TYPE_COUNT);
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
325f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
326f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool ImmersiveFullscreenController::IsEnabled() const {
328f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return enabled_;
329f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
330f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
331f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool ImmersiveFullscreenController::IsRevealed() const {
332f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return enabled_ && reveal_state_ != CLOSED;
333f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
334f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
335f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ImmersiveRevealedLock* ImmersiveFullscreenController::GetRevealedLock(
336f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    AnimateReveal animate_reveal) {
337f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return new ImmersiveRevealedLock(weak_ptr_factory_.GetWeakPtr(),
338f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                   animate_reveal);
339f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
340f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
341f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
342f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Testing interface:
343f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
344f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::SetupForTest() {
345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!enabled_);
346f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  animations_disabled_for_test_ = true;
347f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
348f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Move the mouse off of the top-of-window views so that it does not keep the
349f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // top-of-window views revealed.
350f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::vector<gfx::Rect> bounds_in_screen(
351f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      delegate_->GetVisibleBoundsInScreen());
352f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!bounds_in_screen.empty());
353f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int bottommost_in_screen = bounds_in_screen[0].bottom();
354f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (size_t i = 1; i < bounds_in_screen.size(); ++i) {
355f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (bounds_in_screen[i].bottom() > bottommost_in_screen)
356f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      bottommost_in_screen = bounds_in_screen[i].bottom();
357f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
358f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Point cursor_pos(0, bottommost_in_screen + 100);
359f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  aura::Env::GetInstance()->set_last_mouse_location(cursor_pos);
360a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  UpdateLocatedEventRevealedLock(NULL);
361f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
362f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
363f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
364f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// ui::EventHandler overrides:
365f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
366f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::OnMouseEvent(ui::MouseEvent* event) {
367f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!enabled_)
368f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
369f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
370f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (event->type() != ui::ET_MOUSE_MOVED &&
371f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      event->type() != ui::ET_MOUSE_PRESSED &&
372f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      event->type() != ui::ET_MOUSE_RELEASED &&
373f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) {
374f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
375f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
377a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Mouse hover can initiate revealing the top-of-window views while |widget_|
378a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // is inactive.
379f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
380a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (reveal_state_ == SLIDING_OPEN || reveal_state_ == REVEALED) {
381a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    top_edge_hover_timer_.Stop();
382a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    UpdateLocatedEventRevealedLock(event);
383a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  } else if (event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) {
384a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // Trigger a reveal if the cursor pauses at the top of the screen for a
385a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // while.
386f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    UpdateTopEdgeHoverTimer(event);
387a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
388f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
389f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
390f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::OnTouchEvent(ui::TouchEvent* event) {
391f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!enabled_ || event->type() != ui::ET_TOUCH_PRESSED)
392f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
393f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
394a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Touch should not initiate revealing the top-of-window views while |widget_|
395a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // is inactive.
396a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!widget_->IsActive())
397a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return;
398a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
399a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  UpdateLocatedEventRevealedLock(event);
400f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
401f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
402f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::OnGestureEvent(ui::GestureEvent* event) {
403f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!enabled_)
404f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
405f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
406f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Touch gestures should not initiate revealing the top-of-window views while
407a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // |widget_| is inactive.
408a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!widget_->IsActive())
409f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
410f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
411f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  switch (event->type()) {
412a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#if defined(OS_WIN)
413a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    case ui::ET_GESTURE_WIN8_EDGE_SWIPE:
414a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      UpdateRevealedLocksForSwipe(GetSwipeType(event));
415a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      event->SetHandled();
416a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      break;
417a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#endif
418f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case ui::ET_GESTURE_SCROLL_BEGIN:
419f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (ShouldHandleGestureEvent(GetEventLocationInScreen(*event))) {
420f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        gesture_begun_ = true;
421a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // Do not consume the event. Otherwise, we end up consuming all
422a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // ui::ET_GESTURE_SCROLL_BEGIN events in the top-of-window views
423a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // when the top-of-window views are revealed.
424f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      }
425f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      break;
426f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case ui::ET_GESTURE_SCROLL_UPDATE:
427f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (gesture_begun_) {
428f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (UpdateRevealedLocksForSwipe(GetSwipeType(event)))
429f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          event->SetHandled();
430f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        gesture_begun_ = false;
431f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      }
432f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      break;
433f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case ui::ET_GESTURE_SCROLL_END:
434f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case ui::ET_SCROLL_FLING_START:
435f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      gesture_begun_ = false;
436f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      break;
437f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    default:
438f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      break;
439f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
440f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
441f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
442f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
443f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// views::FocusChangeListener overrides:
444f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
445f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::OnWillChangeFocus(
446f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    views::View* focused_before,
447f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    views::View* focused_now) {
448f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
449f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
450f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::OnDidChangeFocus(
451f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    views::View* focused_before,
452f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    views::View* focused_now) {
453f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UpdateFocusRevealedLock();
454f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
455f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
456f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
457f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// views::WidgetObserver overrides:
458f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
459f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::OnWidgetDestroying(views::Widget* widget) {
460f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EnableWindowObservers(false);
461f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  native_window_ = NULL;
462f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
463f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Set |enabled_| to false such that any calls to MaybeStartReveal() and
464f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // MaybeEndReveal() have no effect.
465f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  enabled_ = false;
466f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
467f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
468f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::OnWidgetActivationChanged(
469f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    views::Widget* widget,
470f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    bool active) {
471f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UpdateFocusRevealedLock();
472f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
473f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
474f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
475f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// gfx::AnimationDelegate overrides:
476f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
477f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::AnimationEnded(
478f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const gfx::Animation* animation) {
479f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (reveal_state_ == SLIDING_OPEN) {
480f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    OnSlideOpenAnimationCompleted();
481f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else if (reveal_state_ == SLIDING_CLOSED) {
482f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    OnSlideClosedAnimationCompleted();
483f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
484f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
485f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
486f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::AnimationProgressed(
487f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const gfx::Animation* animation) {
488f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  delegate_->SetVisibleFraction(animation->GetCurrentValue());
489f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
490f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
491f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
492f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// aura::WindowObserver overrides:
493f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ImmersiveFullscreenController::OnTransientChildAdded(
4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    aura::Window* window,
4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    aura::Window* transient) {
497f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  views::BubbleDelegateView* bubble_delegate = AsBubbleDelegate(transient);
498f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (bubble_delegate &&
499f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      bubble_delegate->GetAnchorView() &&
500f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      top_container_->Contains(bubble_delegate->GetAnchorView())) {
501f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Observe the aura::Window because the BubbleDelegateView may not be
502f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // parented to the widget's root view yet so |bubble_delegate->GetWidget()|
503f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // may still return NULL.
504f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    bubble_manager_->StartObserving(transient);
505f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
506f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
507f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
5085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ImmersiveFullscreenController::OnTransientChildRemoved(
509f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    aura::Window* window,
510f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    aura::Window* transient) {
511f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bubble_manager_->StopObserving(transient);
512f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
513f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
514f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
515f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// ash::ImmersiveRevealedLock::Delegate overrides:
516f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
517f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::LockRevealedState(
518f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    AnimateReveal animate_reveal) {
519f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ++revealed_lock_count_;
520f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  Animate animate = (animate_reveal == ANIMATE_REVEAL_YES) ?
521f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ANIMATE_FAST : ANIMATE_NO;
522f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  MaybeStartReveal(animate);
523f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
524f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
525f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::UnlockRevealedState() {
526f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  --revealed_lock_count_;
527f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK_GE(revealed_lock_count_, 0);
528f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (revealed_lock_count_ == 0) {
529f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Always animate ending the reveal fast.
530f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    MaybeEndReveal(ANIMATE_FAST);
531f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
532f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
533f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
534f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
535f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// private:
536f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
537f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::EnableWindowObservers(bool enable) {
538f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (observers_enabled_ == enable)
539f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
540f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  observers_enabled_ = enable;
541f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
542a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  views::FocusManager* focus_manager = widget_->GetFocusManager();
543f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
544f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (enable) {
545a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    widget_->AddObserver(this);
546f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    focus_manager->AddFocusChangeListener(this);
547f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Shell::GetInstance()->AddPreTargetHandler(this);
548a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ::wm::TransientWindowManager::Get(native_window_)->
5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        AddObserver(this);
550f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
551f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    RecreateBubbleManager();
552f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
553a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    widget_->RemoveObserver(this);
554f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    focus_manager->RemoveFocusChangeListener(this);
555f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Shell::GetInstance()->RemovePreTargetHandler(this);
556a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ::wm::TransientWindowManager::Get(native_window_)->
5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        RemoveObserver(this);
558f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
559f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // We have stopped observing whether transient children are added or removed
560f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // to |native_window_|. The set of bubbles that BubbleManager is observing
561f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // will become stale really quickly. Destroy BubbleManager and recreate it
562f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // when we start observing |native_window_| again.
563f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    bubble_manager_.reset();
564f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
565f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    animation_->Stop();
566f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
567f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
568f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
569f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::UpdateTopEdgeHoverTimer(
570f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ui::MouseEvent* event) {
571f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(enabled_);
572a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK(reveal_state_ == SLIDING_CLOSED || reveal_state_ == CLOSED);
573a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
574a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Check whether |native_window_| is the event target's parent window instead
575a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // of checking for activation. This allows the timer to be started when
576a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // |widget_| is inactive but prevents starting the timer if the mouse is over
577a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // a portion of the top edge obscured by an unrelated widget.
578a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!top_edge_hover_timer_.IsRunning() &&
579a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      !native_window_->Contains(static_cast<aura::Window*>(event->target()))) {
580f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
581f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
582f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
583a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Mouse hover should not initiate revealing the top-of-window views while a
584a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // window has mouse capture.
585a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (aura::client::GetCaptureWindow(native_window_))
586a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return;
587a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
588f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Point location_in_screen = GetEventLocationInScreen(*event);
589f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (ShouldIgnoreMouseEventAtLocation(location_in_screen))
590f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
591f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
592f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Stop the timer if the cursor left the top edge or is on a different
593f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // display.
594f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Rect hit_bounds_in_screen = GetDisplayBoundsInScreen(native_window_);
595f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  hit_bounds_in_screen.set_height(kMouseRevealBoundsHeight);
596f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!hit_bounds_in_screen.Contains(location_in_screen)) {
597f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    top_edge_hover_timer_.Stop();
598f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
599f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
600f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
601f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // The cursor is now at the top of the screen. Consider the cursor "not
602f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // moving" even if it moves a little bit because users don't have perfect
603f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // pointing precision. (The y position is not tested because
604f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // |hit_bounds_in_screen| is short.)
605f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (top_edge_hover_timer_.IsRunning() &&
606f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      abs(location_in_screen.x() - mouse_x_when_hit_top_in_screen_) <=
607f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          kMouseRevealXThresholdPixels)
608f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
609f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
610f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Start the reveal if the cursor doesn't move for some amount of time.
611f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  mouse_x_when_hit_top_in_screen_ = location_in_screen.x();
612f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  top_edge_hover_timer_.Stop();
613f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Timer is stopped when |this| is destroyed, hence Unretained() is safe.
614f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  top_edge_hover_timer_.Start(
615f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      FROM_HERE,
616f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      base::TimeDelta::FromMilliseconds(kMouseRevealDelayMs),
617f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      base::Bind(
618f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          &ImmersiveFullscreenController::AcquireLocatedEventRevealedLock,
619f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          base::Unretained(this)));
620f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
621f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
622f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::UpdateLocatedEventRevealedLock(
623a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    ui::LocatedEvent* event) {
624f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!enabled_)
625f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
626f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!event || event->IsMouseEvent() || event->IsTouchEvent());
627f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
628f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Neither the mouse nor touch can initiate a reveal when the top-of-window
629f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // views are sliding closed or are closed with the following exceptions:
630f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // - Hovering at y = 0 which is handled in OnMouseEvent().
631f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // - Doing a SWIPE_OPEN edge gesture which is handled in OnGestureEvent().
632a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (reveal_state_ == CLOSED || reveal_state_ == SLIDING_CLOSED)
633f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
634f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
635a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // For the sake of simplicity, ignore |widget_|'s activation in computing
636a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // whether the top-of-window views should stay revealed. Ideally, the
637a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // top-of-window views would stay revealed only when the mouse cursor is
638a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // hovered above a non-obscured portion of the top-of-window views. The
639a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // top-of-window views may be partially obscured when |widget_| is inactive.
640f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
641f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Ignore all events while a window has capture. This keeps the top-of-window
642f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // views revealed during a drag.
643f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (aura::client::GetCaptureWindow(native_window_))
644f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
645f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
646f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Point location_in_screen;
647f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (event && event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) {
648f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    location_in_screen = GetEventLocationInScreen(*event);
649f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
650f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(
651f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        native_window_->GetRootWindow());
652f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!cursor_client->IsMouseEventsEnabled()) {
653f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // If mouse events are disabled, the user's last interaction was probably
654f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // via touch. Do no do further processing in this case as there is no easy
655f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // way of retrieving the position of the user's last touch.
656f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return;
657f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
658f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    location_in_screen = aura::Env::GetInstance()->last_mouse_location();
659f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
660f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
661f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if ((!event || event->IsMouseEvent()) &&
662f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ShouldIgnoreMouseEventAtLocation(location_in_screen)) {
663f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
664f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
665f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
666f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // The visible bounds of |top_container_| should be contained in
667f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // |hit_bounds_in_screen|.
668f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::vector<gfx::Rect> hit_bounds_in_screen =
669f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      delegate_->GetVisibleBoundsInScreen();
670f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool keep_revealed = false;
671f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (size_t i = 0; i < hit_bounds_in_screen.size(); ++i) {
672f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Allow the cursor to move slightly off the top-of-window views before
673f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // sliding closed. In the case of ImmersiveModeControllerAsh, this helps
674f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // when the user is attempting to click on the bookmark bar and overshoots
675f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // slightly.
676f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (event && event->type() == ui::ET_MOUSE_MOVED) {
677f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      const int kBoundsOffsetY = 8;
678f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      hit_bounds_in_screen[i].Inset(0, 0, 0, -kBoundsOffsetY);
679f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
680f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
681f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (hit_bounds_in_screen[i].Contains(location_in_screen)) {
682f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      keep_revealed = true;
683f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      break;
684f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
685f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
686f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
687f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (keep_revealed)
688f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    AcquireLocatedEventRevealedLock();
689f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  else
690f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    located_event_revealed_lock_.reset();
691f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
692f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
693f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::AcquireLocatedEventRevealedLock() {
694f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // CAUTION: Acquiring the lock results in a reentrant call to
695f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // AcquireLocatedEventRevealedLock() when
696f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // |ImmersiveFullscreenController::animations_disabled_for_test_| is true.
697f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!located_event_revealed_lock_.get())
698f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    located_event_revealed_lock_.reset(GetRevealedLock(ANIMATE_REVEAL_YES));
699f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
700f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
701f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::UpdateFocusRevealedLock() {
702f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!enabled_)
703f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
704f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
705f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool hold_lock = false;
706a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (widget_->IsActive()) {
707a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    views::View* focused_view = widget_->GetFocusManager()->GetFocusedView();
708f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (top_container_->Contains(focused_view))
709f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      hold_lock = true;
710f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
711f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    aura::Window* active_window = aura::client::GetActivationClient(
712f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        native_window_->GetRootWindow())->GetActiveWindow();
713f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    views::BubbleDelegateView* bubble_delegate =
714f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        AsBubbleDelegate(active_window);
715f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (bubble_delegate && bubble_delegate->anchor_widget()) {
716f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // BubbleManager will already have locked the top-of-window views if the
717f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // bubble is anchored to a child of |top_container_|. Don't acquire
718f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // |focus_revealed_lock_| here for the sake of simplicity.
719f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Note: Instead of checking for the existence of the |anchor_view|,
720f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // the existence of the |anchor_widget| is performed to avoid the case
721f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // where the view is already gone (and the widget is still running).
722f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    } else {
723f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // The currently active window is not |native_window_| and it is not a
724f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // bubble with an anchor view. The top-of-window views should be revealed
725f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // if:
726f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // 1) The active window is a transient child of |native_window_|.
727f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // 2) The top-of-window views are already revealed. This restriction
728f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      //    prevents a transient window opened by the web contents while the
729f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      //    top-of-window views are hidden from from initiating a reveal.
730f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // The top-of-window views will stay revealed till |native_window_| is
731f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // reactivated.
732f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (IsRevealed() &&
733f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          IsWindowTransientChildOf(active_window, native_window_)) {
734f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        hold_lock = true;
735f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      }
736f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
737f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
738f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
739f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (hold_lock) {
740f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!focus_revealed_lock_.get())
741f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      focus_revealed_lock_.reset(GetRevealedLock(ANIMATE_REVEAL_YES));
742f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
743f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    focus_revealed_lock_.reset();
744f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
745f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
746f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
747f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool ImmersiveFullscreenController::UpdateRevealedLocksForSwipe(
748f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    SwipeType swipe_type) {
749f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!enabled_ || swipe_type == SWIPE_NONE)
750f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
751f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
752f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Swipes while |native_window_| is inactive should have been filtered out in
753f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // OnGestureEvent().
754a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK(widget_->IsActive());
755f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
756f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (reveal_state_ == SLIDING_CLOSED || reveal_state_ == CLOSED) {
757f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (swipe_type == SWIPE_OPEN && !located_event_revealed_lock_.get()) {
758f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      located_event_revealed_lock_.reset(GetRevealedLock(ANIMATE_REVEAL_YES));
759f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return true;
760f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
761f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
762f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (swipe_type == SWIPE_CLOSE) {
763f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Attempt to end the reveal. If other code is holding onto a lock, the
764f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // attempt will be unsuccessful.
765f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      located_event_revealed_lock_.reset();
766f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      focus_revealed_lock_.reset();
767f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
768a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (reveal_state_ == SLIDING_CLOSED || reveal_state_ == CLOSED) {
769a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        widget_->GetFocusManager()->ClearFocus();
770f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        return true;
771a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
772f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
773f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Ending the reveal was unsuccessful. Reaquire the locks if appropriate.
774a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      UpdateLocatedEventRevealedLock(NULL);
775f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      UpdateFocusRevealedLock();
776f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
777f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
778f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return false;
779f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
780f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
781f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)int ImmersiveFullscreenController::GetAnimationDuration(Animate animate) const {
782f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  switch (animate) {
783f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case ANIMATE_NO:
784f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return 0;
785f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case ANIMATE_SLOW:
786f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return kRevealSlowAnimationDurationMs;
787f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case ANIMATE_FAST:
788f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return kRevealFastAnimationDurationMs;
789f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
790f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  NOTREACHED();
791f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return 0;
792f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
793f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
794f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::MaybeStartReveal(Animate animate) {
795f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!enabled_)
796f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
797f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
798f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (animations_disabled_for_test_)
799f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    animate = ANIMATE_NO;
800f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
801f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Callers with ANIMATE_NO expect this function to synchronously reveal the
802f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // top-of-window views.
803f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (reveal_state_ == REVEALED ||
804f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      (reveal_state_ == SLIDING_OPEN && animate != ANIMATE_NO)) {
805f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
806f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
807f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
808f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RevealState previous_reveal_state = reveal_state_;
809f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  reveal_state_ = SLIDING_OPEN;
810f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (previous_reveal_state == CLOSED) {
811f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    delegate_->OnImmersiveRevealStarted();
812f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
813f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Do not do any more processing if OnImmersiveRevealStarted() changed
814f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // |reveal_state_|.
815f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (reveal_state_ != SLIDING_OPEN)
816f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return;
817f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
818f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Slide in the reveal view.
819f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (animate == ANIMATE_NO) {
820f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    animation_->Reset(1);
821f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    OnSlideOpenAnimationCompleted();
822f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
823f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    animation_->SetSlideDuration(GetAnimationDuration(animate));
824f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    animation_->Show();
825f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
826f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
827f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
828f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::OnSlideOpenAnimationCompleted() {
829f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK_EQ(SLIDING_OPEN, reveal_state_);
830f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  reveal_state_ = REVEALED;
831f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  delegate_->SetVisibleFraction(1);
832f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
833f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // The user may not have moved the mouse since the reveal was initiated.
834f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Update the revealed lock to reflect the mouse's current state.
835a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  UpdateLocatedEventRevealedLock(NULL);
836f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
837f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
838f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::MaybeEndReveal(Animate animate) {
839f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!enabled_ || revealed_lock_count_ != 0)
840f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
841f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
842f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (animations_disabled_for_test_)
843f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    animate = ANIMATE_NO;
844f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
845f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Callers with ANIMATE_NO expect this function to synchronously close the
846f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // top-of-window views.
847f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (reveal_state_ == CLOSED ||
848f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      (reveal_state_ == SLIDING_CLOSED && animate != ANIMATE_NO)) {
849f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
850f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
851f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
852f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  reveal_state_ = SLIDING_CLOSED;
853f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int duration_ms = GetAnimationDuration(animate);
854f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (duration_ms > 0) {
855f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    animation_->SetSlideDuration(duration_ms);
856f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    animation_->Hide();
857f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
858f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    animation_->Reset(0);
859f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    OnSlideClosedAnimationCompleted();
860f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
861f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
862f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
863f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::OnSlideClosedAnimationCompleted() {
864f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK_EQ(SLIDING_CLOSED, reveal_state_);
865f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  reveal_state_ = CLOSED;
866f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  delegate_->OnImmersiveRevealEnded();
867f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
868f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
869f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ImmersiveFullscreenController::SwipeType
870f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ImmersiveFullscreenController::GetSwipeType(ui::GestureEvent* event) const {
871a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#if defined(OS_WIN)
872a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (event->type() == ui::ET_GESTURE_WIN8_EDGE_SWIPE)
873a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    return SWIPE_OPEN;
874a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#endif
875f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (event->type() != ui::ET_GESTURE_SCROLL_UPDATE)
876f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return SWIPE_NONE;
877f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Make sure that it is a clear vertical gesture.
878cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (std::abs(event->details().scroll_y()) <=
879cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      kSwipeVerticalThresholdMultiplier * std::abs(event->details().scroll_x()))
880f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return SWIPE_NONE;
881f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (event->details().scroll_y() < 0)
882f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return SWIPE_CLOSE;
883f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  else if (event->details().scroll_y() > 0)
884f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return SWIPE_OPEN;
885f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return SWIPE_NONE;
886f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
887f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
888f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool ImmersiveFullscreenController::ShouldIgnoreMouseEventAtLocation(
889f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const gfx::Point& location) const {
890f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Ignore mouse events in the region immediately above the top edge of the
891f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // display. This is to handle the case of a user with a vertical display
892f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // layout (primary display above/below secondary display) and the immersive
893f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // fullscreen window on the bottom display. It is really hard to trigger a
894f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // reveal in this case because:
895f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // - It is hard to stop the cursor in the top |kMouseRevealBoundsHeight|
896f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  //   pixels of the bottom display.
897f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // - The cursor is warped to the top display if the cursor gets to the top
898f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  //   edge of the bottom display.
899f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Mouse events are ignored in the bottom few pixels of the top display
900f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // (Mouse events in this region cannot start or end a reveal). This allows a
901f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // user to overshoot the top of the bottom display and still reveal the
902f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // top-of-window views.
903f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Rect dead_region = GetDisplayBoundsInScreen(native_window_);
904f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  dead_region.set_y(dead_region.y() - kHeightOfDeadRegionAboveTopContainer);
905f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  dead_region.set_height(kHeightOfDeadRegionAboveTopContainer);
906f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return dead_region.Contains(location);
907f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
908f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
909f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool ImmersiveFullscreenController::ShouldHandleGestureEvent(
910f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const gfx::Point& location) const {
911a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK(widget_->IsActive());
912f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (reveal_state_ == REVEALED) {
913f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    std::vector<gfx::Rect> hit_bounds_in_screen(
914f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        delegate_->GetVisibleBoundsInScreen());
915f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    for (size_t i = 0; i < hit_bounds_in_screen.size(); ++i) {
916f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (hit_bounds_in_screen[i].Contains(location))
917f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        return true;
918f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
919f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
920f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
921f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
922f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // When the top-of-window views are not fully revealed, handle gestures which
923f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // start in the top few pixels of the screen.
924f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Rect hit_bounds_in_screen(GetDisplayBoundsInScreen(native_window_));
9255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  hit_bounds_in_screen.set_height(kImmersiveFullscreenTopEdgeInset);
926f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (hit_bounds_in_screen.Contains(location))
927f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return true;
928f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
929f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // There may be a bezel sensor off screen logically above
930f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // |hit_bounds_in_screen|. The check for the event not contained by the
931f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // closest screen ensures that the event is from a valid bezel (as opposed to
932f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // another screen in an extended desktop).
933f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Rect screen_bounds =
934f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      Shell::GetScreen()->GetDisplayNearestPoint(location).bounds();
935f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return (!screen_bounds.Contains(location) &&
936f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          location.y() < hit_bounds_in_screen.y() &&
937f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          location.x() >= hit_bounds_in_screen.x() &&
938f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          location.x() < hit_bounds_in_screen.right());
939f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
940f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
941f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ImmersiveFullscreenController::RecreateBubbleManager() {
942f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bubble_manager_.reset(new BubbleManager(this));
943f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const std::vector<aura::Window*> transient_children =
944a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ::wm::GetTransientChildren(native_window_);
945f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (size_t i = 0; i < transient_children.size(); ++i) {
946f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    aura::Window* transient_child = transient_children[i];
947f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    views::BubbleDelegateView* bubble_delegate =
948f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        AsBubbleDelegate(transient_child);
949f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (bubble_delegate &&
950f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        bubble_delegate->GetAnchorView() &&
951f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        top_container_->Contains(bubble_delegate->GetAnchorView())) {
952f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      bubble_manager_->StartObserving(transient_child);
953f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
954f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
955f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
956f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
957f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}  // namespace ash
958