OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h" | 5 #include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h" |
6 | 6 |
7 #include "ash/ash_switches.h" | 7 #include "ash/ash_switches.h" |
8 #include "ash/shell.h" | 8 #include "ash/shell.h" |
9 #include "ash/wm/window_properties.h" | 9 #include "ash/wm/window_properties.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 27 matching lines...) Expand all Loading... |
38 // few pixels before the view goes completely off the screen, which reduces | 38 // few pixels before the view goes completely off the screen, which reduces |
39 // the visual "pop" as the 2-pixel tall immersive-style tabs become visible. | 39 // the visual "pop" as the 2-pixel tall immersive-style tabs become visible. |
40 const int kAnimationOffsetY = 3; | 40 const int kAnimationOffsetY = 3; |
41 | 41 |
42 // Duration for the reveal show/hide slide animation. The slower duration is | 42 // Duration for the reveal show/hide slide animation. The slower duration is |
43 // used for the initial slide out to give the user more change to see what | 43 // used for the initial slide out to give the user more change to see what |
44 // happened. | 44 // happened. |
45 const int kRevealSlowAnimationDurationMs = 400; | 45 const int kRevealSlowAnimationDurationMs = 400; |
46 const int kRevealFastAnimationDurationMs = 200; | 46 const int kRevealFastAnimationDurationMs = 200; |
47 | 47 |
| 48 // If |hovered| is true, moves the mouse above |view|. Moves it outside of |
| 49 // |view| otherwise. |
| 50 // Should not be called outside of tests. |
| 51 void MoveMouse(views::View* view, bool hovered) { |
| 52 gfx::Point cursor_pos; |
| 53 if (!hovered) { |
| 54 int bottom_edge = view->bounds().bottom(); |
| 55 cursor_pos = gfx::Point(0, bottom_edge + 100); |
| 56 } |
| 57 views::View::ConvertPointToScreen(view, &cursor_pos); |
| 58 aura::Env::GetInstance()->set_last_mouse_location(cursor_pos); |
| 59 } |
| 60 |
48 // Returns true if the currently active window is a transient child of | 61 // Returns true if the currently active window is a transient child of |
49 // |toplevel|. | 62 // |toplevel|. |
50 bool IsActiveWindowTransientChildOf(gfx::NativeWindow toplevel) { | 63 bool IsActiveWindowTransientChildOf(aura::Window* toplevel) { |
51 aura::Window* active_window = aura::client::GetActivationClient( | 64 aura::Window* active_window = aura::client::GetActivationClient( |
52 toplevel->GetRootWindow())->GetActiveWindow(); | 65 toplevel->GetRootWindow())->GetActiveWindow(); |
53 | 66 |
54 if (!toplevel || !active_window) | 67 if (!toplevel || !active_window) |
55 return false; | 68 return false; |
56 | 69 |
57 for (aura::Window* window = active_window; window; | 70 for (aura::Window* window = active_window; window; |
58 window = window->transient_parent()) { | 71 window = window->transient_parent()) { |
59 if (window == toplevel) | 72 if (window == toplevel) |
60 return true; | 73 return true; |
(...skipping 20 matching lines...) Expand all Loading... |
81 private: | 94 private: |
82 base::WeakPtr<ImmersiveModeControllerAsh> controller_; | 95 base::WeakPtr<ImmersiveModeControllerAsh> controller_; |
83 | 96 |
84 DISALLOW_COPY_AND_ASSIGN(RevealedLockAsh); | 97 DISALLOW_COPY_AND_ASSIGN(RevealedLockAsh); |
85 }; | 98 }; |
86 | 99 |
87 } // namespace | 100 } // namespace |
88 | 101 |
89 //////////////////////////////////////////////////////////////////////////////// | 102 //////////////////////////////////////////////////////////////////////////////// |
90 | 103 |
| 104 // Manages widgets which should move in sync with the top-of-window views. |
| 105 class ImmersiveModeControllerAsh::AnchoredWidgetManager |
| 106 : public views::WidgetObserver { |
| 107 public: |
| 108 explicit AnchoredWidgetManager(ImmersiveModeControllerAsh* controller); |
| 109 virtual ~AnchoredWidgetManager(); |
| 110 |
| 111 // Anchors |widget| such that it stays |y_offset| below the top-of-window |
| 112 // views. |widget| will be repositioned whenever the top-of-window views are |
| 113 // animated (top-of-window views revealing / unrevealing) or the top-of-window |
| 114 // bounds change (eg the bookmark bar is shown). |
| 115 // If the top-of-window views are revealed (or become revealed), |widget| will |
| 116 // keep the top-of-window views revealed till |widget| is hidden or |
| 117 // RemoveAnchoredWidget() is called. |
| 118 void AddAnchoredWidget(views::Widget* widget, int y_offset); |
| 119 |
| 120 // Stops managing |widget|'s y position. |
| 121 // Closes the top-of-window views if no locks or other anchored widgets are |
| 122 // keeping the top-of-window views revealed. |
| 123 void RemoveAnchoredWidget(views::Widget* widget); |
| 124 |
| 125 // Adjusts the y positions of the anchored widgets for the new top container |
| 126 // bounds. |
| 127 void OnTopContainerBoundsChanged(); |
| 128 |
| 129 const std::set<views::Widget*>& visible_anchored_widgets() const { |
| 130 return visible_; |
| 131 } |
| 132 |
| 133 private: |
| 134 // Updates |revealed_lock_| based on the visible anchored widgets. |
| 135 void UpdateRevealedLock(); |
| 136 |
| 137 // Updates the y position of |widget| given |y_offset| and the top |
| 138 // container's target bounds. |
| 139 void UpdateWidgetBounds(views::Widget* widget, int y_offset); |
| 140 |
| 141 // views::WidgetObserver overrides: |
| 142 virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE; |
| 143 virtual void OnWidgetVisibilityChanged(views::Widget* widget, |
| 144 bool visible) OVERRIDE; |
| 145 |
| 146 ImmersiveModeControllerAsh* controller_; |
| 147 |
| 148 // Mapping of anchored widgets to the y offset below the top-of-window views |
| 149 // that they should be positioned at. |
| 150 std::map<views::Widget*, int> widgets_; |
| 151 |
| 152 // The subset of |widgets_| which are visible. |
| 153 std::set<views::Widget*> visible_; |
| 154 |
| 155 // Lock which keeps the top-of-window views revealed based on the visible |
| 156 // anchored widgets. |
| 157 scoped_ptr<ImmersiveModeController::RevealedLock> revealed_lock_; |
| 158 |
| 159 DISALLOW_COPY_AND_ASSIGN(AnchoredWidgetManager); |
| 160 }; |
| 161 |
| 162 ImmersiveModeControllerAsh::AnchoredWidgetManager::AnchoredWidgetManager( |
| 163 ImmersiveModeControllerAsh* controller) |
| 164 : controller_(controller) { |
| 165 } |
| 166 |
| 167 ImmersiveModeControllerAsh::AnchoredWidgetManager::~AnchoredWidgetManager() { |
| 168 for (std::map<views::Widget*, int>::iterator it = widgets_.begin(); |
| 169 it != widgets_.end(); ++it) { |
| 170 RemoveAnchoredWidget(it->first); |
| 171 } |
| 172 } |
| 173 |
| 174 void ImmersiveModeControllerAsh::AnchoredWidgetManager::AddAnchoredWidget( |
| 175 views::Widget* widget, |
| 176 int y_offset) { |
| 177 DCHECK(widget); |
| 178 bool already_added = widgets_.count(widget) > 0; |
| 179 widgets_[widget] = y_offset; |
| 180 |
| 181 if (already_added) |
| 182 return; |
| 183 |
| 184 widget->AddObserver(this); |
| 185 |
| 186 if (widget->IsVisible()) |
| 187 visible_.insert(widget); |
| 188 |
| 189 UpdateRevealedLock(); |
| 190 UpdateWidgetBounds(widget, y_offset); |
| 191 } |
| 192 |
| 193 void ImmersiveModeControllerAsh::AnchoredWidgetManager::RemoveAnchoredWidget( |
| 194 views::Widget* widget) { |
| 195 if (!widgets_.count(widget)) |
| 196 return; |
| 197 |
| 198 widget->RemoveObserver(this); |
| 199 widgets_.erase(widget); |
| 200 visible_.erase(widget); |
| 201 |
| 202 UpdateRevealedLock(); |
| 203 } |
| 204 |
| 205 void ImmersiveModeControllerAsh::AnchoredWidgetManager:: |
| 206 OnTopContainerBoundsChanged() { |
| 207 for (std::map<views::Widget*, int>::iterator it = widgets_.begin(); |
| 208 it != widgets_.end(); ++it) { |
| 209 UpdateWidgetBounds(it->first, it->second); |
| 210 } |
| 211 |
| 212 UpdateRevealedLock(); |
| 213 } |
| 214 |
| 215 void ImmersiveModeControllerAsh::AnchoredWidgetManager::UpdateRevealedLock() { |
| 216 if (visible_.empty()) { |
| 217 revealed_lock_.reset(); |
| 218 } else if (controller_->IsRevealed()) { |
| 219 // It is hard to determine the required initial transforms and the required |
| 220 // durations of the animations of |visible_| such that they appear to be |
| 221 // anchored to the top-of-window views while the top-of-window views are |
| 222 // animating. Skip to the end of the reveal animation instead. |
| 223 // We do not query the controller's reveal state because we may be called |
| 224 // as a result of LayoutBrowserView() in MaybeStartReveal() when |
| 225 // |reveal_state_| is SLIDING_OPEN but no animation is running yet. |
| 226 ui::Layer* top_container_layer = |
| 227 controller_->browser_view_->top_container()->layer(); |
| 228 if (top_container_layer && |
| 229 top_container_layer->GetAnimator()->is_animating()) { |
| 230 controller_->MaybeRevealWithoutAnimation(); |
| 231 } |
| 232 |
| 233 if (!revealed_lock_.get()) |
| 234 revealed_lock_.reset(controller_->GetRevealedLock()); |
| 235 } |
| 236 } |
| 237 |
| 238 void ImmersiveModeControllerAsh::AnchoredWidgetManager::UpdateWidgetBounds( |
| 239 views::Widget* widget, |
| 240 int y_offset) { |
| 241 if (!widget->IsVisible()) |
| 242 return; |
| 243 |
| 244 gfx::Rect top_container_target_bounds = |
| 245 controller_->browser_view_->top_container()->GetTargetBoundsInScreen(); |
| 246 gfx::Rect bounds(widget->GetWindowBoundsInScreen()); |
| 247 bounds.set_y( |
| 248 top_container_target_bounds.bottom() + y_offset); |
| 249 widget->SetBounds(bounds); |
| 250 } |
| 251 |
| 252 void ImmersiveModeControllerAsh::AnchoredWidgetManager::OnWidgetDestroying( |
| 253 views::Widget* widget) { |
| 254 RemoveAnchoredWidget(widget); |
| 255 } |
| 256 |
| 257 void ImmersiveModeControllerAsh::AnchoredWidgetManager:: |
| 258 OnWidgetVisibilityChanged( |
| 259 views::Widget* widget, |
| 260 bool visible) { |
| 261 if (visible) |
| 262 visible_.insert(widget); |
| 263 else |
| 264 visible_.erase(widget); |
| 265 |
| 266 UpdateRevealedLock(); |
| 267 |
| 268 std::map<views::Widget*, int>::iterator it = widgets_.find(widget); |
| 269 DCHECK(it != widgets_.end()); |
| 270 UpdateWidgetBounds(it->first, it->second); |
| 271 } |
| 272 |
| 273 //////////////////////////////////////////////////////////////////////////////// |
| 274 |
91 // Observer to watch for window restore. views::Widget does not provide a hook | 275 // Observer to watch for window restore. views::Widget does not provide a hook |
92 // to observe for window restore, so do this at the Aura level. | 276 // to observe for window restore, so do this at the Aura level. |
93 class ImmersiveModeControllerAsh::WindowObserver : public aura::WindowObserver { | 277 class ImmersiveModeControllerAsh::WindowObserver : public aura::WindowObserver { |
94 public: | 278 public: |
95 explicit WindowObserver(ImmersiveModeControllerAsh* controller) | 279 explicit WindowObserver(ImmersiveModeControllerAsh* controller) |
96 : controller_(controller) { | 280 : controller_(controller) { |
97 controller_->native_window_->AddObserver(this); | 281 controller_->native_window_->AddObserver(this); |
98 } | 282 } |
99 | 283 |
100 virtual ~WindowObserver() { | 284 virtual ~WindowObserver() { |
(...skipping 25 matching lines...) Expand all Loading... |
126 } | 310 } |
127 | 311 |
128 private: | 312 private: |
129 ImmersiveModeControllerAsh* controller_; // Not owned. | 313 ImmersiveModeControllerAsh* controller_; // Not owned. |
130 | 314 |
131 DISALLOW_COPY_AND_ASSIGN(WindowObserver); | 315 DISALLOW_COPY_AND_ASSIGN(WindowObserver); |
132 }; | 316 }; |
133 | 317 |
134 //////////////////////////////////////////////////////////////////////////////// | 318 //////////////////////////////////////////////////////////////////////////////// |
135 | 319 |
136 class ImmersiveModeControllerAsh::AnimationObserver | |
137 : public ui::ImplicitAnimationObserver { | |
138 public: | |
139 enum AnimationType { | |
140 SLIDE_OPEN, | |
141 SLIDE_CLOSED, | |
142 }; | |
143 | |
144 AnimationObserver(ImmersiveModeControllerAsh* controller, AnimationType type) | |
145 : controller_(controller), animation_type_(type) {} | |
146 virtual ~AnimationObserver() {} | |
147 | |
148 // ui::ImplicitAnimationObserver overrides: | |
149 virtual void OnImplicitAnimationsCompleted() OVERRIDE { | |
150 if (animation_type_ == SLIDE_OPEN) | |
151 controller_->OnSlideOpenAnimationCompleted(); | |
152 else if (animation_type_ == SLIDE_CLOSED) | |
153 controller_->OnSlideClosedAnimationCompleted(); | |
154 else | |
155 NOTREACHED(); | |
156 } | |
157 | |
158 private: | |
159 ImmersiveModeControllerAsh* controller_; | |
160 AnimationType animation_type_; | |
161 | |
162 DISALLOW_COPY_AND_ASSIGN(AnimationObserver); | |
163 }; | |
164 | |
165 //////////////////////////////////////////////////////////////////////////////// | |
166 | |
167 ImmersiveModeControllerAsh::ImmersiveModeControllerAsh() | 320 ImmersiveModeControllerAsh::ImmersiveModeControllerAsh() |
168 : browser_view_(NULL), | 321 : browser_view_(NULL), |
169 enabled_(false), | 322 enabled_(false), |
170 reveal_state_(CLOSED), | 323 reveal_state_(CLOSED), |
171 revealed_lock_count_(0), | 324 revealed_lock_count_(0), |
172 hide_tab_indicators_(false), | 325 hide_tab_indicators_(false), |
173 native_window_(NULL), | 326 native_window_(NULL), |
174 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | 327 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
175 } | 328 } |
176 | 329 |
177 ImmersiveModeControllerAsh::~ImmersiveModeControllerAsh() { | 330 ImmersiveModeControllerAsh::~ImmersiveModeControllerAsh() { |
178 // The browser view is being destroyed so there's no need to update its | 331 // The browser view is being destroyed so there's no need to update its |
179 // layout or layers, even if the top views are revealed. But the window | 332 // layout or layers, even if the top views are revealed. But the window |
180 // observers still need to be removed. | 333 // observers still need to be removed. |
181 EnableWindowObservers(false); | 334 EnableWindowObservers(false); |
182 } | 335 } |
183 | 336 |
184 void ImmersiveModeControllerAsh::LockRevealedState() { | 337 void ImmersiveModeControllerAsh::LockRevealedState() { |
185 ++revealed_lock_count_; | 338 ++revealed_lock_count_; |
186 if (revealed_lock_count_ == 1) | 339 if (revealed_lock_count_ == 1) |
187 MaybeStartReveal(); | 340 MaybeStartReveal(ANIMATE_FAST); |
188 } | 341 } |
189 | 342 |
190 void ImmersiveModeControllerAsh::UnlockRevealedState() { | 343 void ImmersiveModeControllerAsh::UnlockRevealedState() { |
191 --revealed_lock_count_; | 344 --revealed_lock_count_; |
192 DCHECK_GE(revealed_lock_count_, 0); | 345 DCHECK_GE(revealed_lock_count_, 0); |
193 if (revealed_lock_count_ == 0) | 346 if (revealed_lock_count_ == 0) |
194 MaybeEndReveal(ANIMATE_FAST); | 347 MaybeEndReveal(ANIMATE_FAST); |
195 } | 348 } |
196 | 349 |
| 350 void ImmersiveModeControllerAsh::MaybeRevealWithoutAnimation() { |
| 351 MaybeStartReveal(ANIMATE_NO); |
| 352 } |
| 353 |
197 void ImmersiveModeControllerAsh::Init(BrowserView* browser_view) { | 354 void ImmersiveModeControllerAsh::Init(BrowserView* browser_view) { |
198 browser_view_ = browser_view; | 355 browser_view_ = browser_view; |
199 // Browser view is detached from its widget during destruction. Cache the | 356 // Browser view is detached from its widget during destruction. Cache the |
200 // window pointer so |this| can stop observing during destruction. | 357 // window pointer so |this| can stop observing during destruction. |
201 native_window_ = browser_view_->GetNativeWindow(); | 358 native_window_ = browser_view_->GetNativeWindow(); |
202 DCHECK(native_window_); | 359 DCHECK(native_window_); |
203 EnableWindowObservers(true); | 360 EnableWindowObservers(true); |
204 | 361 |
205 slide_open_observer_.reset( | |
206 new AnimationObserver(this, AnimationObserver::SLIDE_OPEN)); | |
207 slide_closed_observer_.reset( | |
208 new AnimationObserver(this, AnimationObserver::SLIDE_CLOSED)); | |
209 | |
210 // Optionally allow the tab indicators to be hidden. | 362 // Optionally allow the tab indicators to be hidden. |
211 hide_tab_indicators_ = CommandLine::ForCurrentProcess()-> | 363 hide_tab_indicators_ = CommandLine::ForCurrentProcess()-> |
212 HasSwitch(ash::switches::kAshImmersiveHideTabIndicators); | 364 HasSwitch(ash::switches::kAshImmersiveHideTabIndicators); |
| 365 |
| 366 anchored_widget_manager_.reset(new AnchoredWidgetManager(this)); |
213 } | 367 } |
214 | 368 |
215 void ImmersiveModeControllerAsh::SetEnabled(bool enabled) { | 369 void ImmersiveModeControllerAsh::SetEnabled(bool enabled) { |
216 DCHECK(browser_view_) << "Must initialize before enabling"; | 370 DCHECK(browser_view_) << "Must initialize before enabling"; |
217 if (enabled_ == enabled) | 371 if (enabled_ == enabled) |
218 return; | 372 return; |
219 enabled_ = enabled; | 373 enabled_ = enabled; |
220 | 374 |
221 if (enabled_) { | 375 if (enabled_) { |
222 // Animate enabling immersive mode by sliding out the top-of-window views. | 376 // Animate enabling immersive mode by sliding out the top-of-window views. |
223 // No animation occurs if a lock is holding the top-of-window views open. | 377 // No animation occurs if a lock is holding the top-of-window views open. |
224 | 378 |
225 // Do a reveal to set the initial state for the animation. (And any | 379 // Do a reveal to set the initial state for the animation. (And any |
226 // required state in case the animation cannot run because of a lock holding | 380 // required state in case the animation cannot run because of a lock holding |
227 // the top-of-window views open.) | 381 // the top-of-window views open.) |
228 StartReveal(ANIMATE_NO); | 382 MaybeStartReveal(ANIMATE_NO); |
229 | 383 |
230 // Reset the mouse and the focus revealed locks so that they do not affect | 384 // Reset the mouse and the focus revealed locks so that they do not affect |
231 // whether the top-of-window views are hidden. Reacquire the locks if ending | 385 // whether the top-of-window views are hidden. Reacquire the locks if ending |
232 // the reveal is unsuccessful. | 386 // the reveal is unsuccessful. |
233 bool had_mouse_revealed_lock = (mouse_revealed_lock_.get() != NULL); | 387 bool had_mouse_revealed_lock = (mouse_revealed_lock_.get() != NULL); |
234 bool had_focus_revealed_lock = (focus_revealed_lock_.get() != NULL); | 388 bool had_focus_revealed_lock = (focus_revealed_lock_.get() != NULL); |
235 mouse_revealed_lock_.reset(); | 389 mouse_revealed_lock_.reset(); |
236 focus_revealed_lock_.reset(); | 390 focus_revealed_lock_.reset(); |
237 | 391 |
238 // Try doing the animation. | 392 // Try doing the animation. |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 if (reveal_layer) | 442 if (reveal_layer) |
289 reveal_layer->parent()->StackAtTop(reveal_layer); | 443 reveal_layer->parent()->StackAtTop(reveal_layer); |
290 } | 444 } |
291 } | 445 } |
292 | 446 |
293 ImmersiveModeControllerAsh::RevealedLock* | 447 ImmersiveModeControllerAsh::RevealedLock* |
294 ImmersiveModeControllerAsh::GetRevealedLock() { | 448 ImmersiveModeControllerAsh::GetRevealedLock() { |
295 return new RevealedLockAsh(weak_ptr_factory_.GetWeakPtr()); | 449 return new RevealedLockAsh(weak_ptr_factory_.GetWeakPtr()); |
296 } | 450 } |
297 | 451 |
| 452 void ImmersiveModeControllerAsh::AnchorWidgetToTopContainer( |
| 453 views::Widget* widget, |
| 454 int y_offset) { |
| 455 anchored_widget_manager_->AddAnchoredWidget(widget, y_offset); |
| 456 } |
| 457 |
| 458 void ImmersiveModeControllerAsh::UnanchorWidgetFromTopContainer( |
| 459 views::Widget* widget) { |
| 460 anchored_widget_manager_->RemoveAnchoredWidget(widget); |
| 461 } |
| 462 |
| 463 void ImmersiveModeControllerAsh::OnTopContainerBoundsChanged() { |
| 464 anchored_widget_manager_->OnTopContainerBoundsChanged(); |
| 465 } |
| 466 |
298 //////////////////////////////////////////////////////////////////////////////// | 467 //////////////////////////////////////////////////////////////////////////////// |
299 // Observers: | 468 // Observers: |
300 | 469 |
301 void ImmersiveModeControllerAsh::OnMouseEvent(ui::MouseEvent* event) { | 470 void ImmersiveModeControllerAsh::OnMouseEvent(ui::MouseEvent* event) { |
302 if (!enabled_) | 471 if (!enabled_) |
303 return; | 472 return; |
304 | 473 |
305 if (event->flags() & ui::EF_IS_SYNTHESIZED) | 474 if (event->flags() & ui::EF_IS_SYNTHESIZED) |
306 return; | 475 return; |
307 | 476 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
362 bool active) { | 531 bool active) { |
363 // Mouse hover should not initiate revealing the top-of-window views while | 532 // Mouse hover should not initiate revealing the top-of-window views while |
364 // |native_window_| is inactive. | 533 // |native_window_| is inactive. |
365 top_timer_.Stop(); | 534 top_timer_.Stop(); |
366 | 535 |
367 UpdateMouseRevealedLock(true); | 536 UpdateMouseRevealedLock(true); |
368 UpdateFocusRevealedLock(); | 537 UpdateFocusRevealedLock(); |
369 } | 538 } |
370 | 539 |
371 //////////////////////////////////////////////////////////////////////////////// | 540 //////////////////////////////////////////////////////////////////////////////// |
| 541 // Animation observer: |
| 542 |
| 543 void ImmersiveModeControllerAsh::OnImplicitAnimationsCompleted() { |
| 544 if (reveal_state_ == SLIDING_OPEN) |
| 545 OnSlideOpenAnimationCompleted(); |
| 546 else if (reveal_state_ == SLIDING_CLOSED) |
| 547 OnSlideClosedAnimationCompleted(); |
| 548 } |
| 549 |
| 550 //////////////////////////////////////////////////////////////////////////////// |
372 // Testing interface: | 551 // Testing interface: |
373 | 552 |
374 void ImmersiveModeControllerAsh::SetHideTabIndicatorsForTest(bool hide) { | 553 void ImmersiveModeControllerAsh::SetHideTabIndicatorsForTest(bool hide) { |
375 hide_tab_indicators_ = hide; | 554 hide_tab_indicators_ = hide; |
376 } | 555 } |
377 | 556 |
378 void ImmersiveModeControllerAsh::StartRevealForTest(bool hovered) { | 557 void ImmersiveModeControllerAsh::StartRevealForTest(bool hovered) { |
379 StartReveal(ANIMATE_NO); | 558 MaybeStartReveal(ANIMATE_NO); |
380 SetMouseHoveredForTest(hovered); | 559 MoveMouse(browser_view_->top_container(), hovered); |
| 560 UpdateMouseRevealedLock(false); |
381 } | 561 } |
382 | 562 |
383 void ImmersiveModeControllerAsh::SetMouseHoveredForTest(bool hovered) { | 563 void ImmersiveModeControllerAsh::SetMouseHoveredForTest(bool hovered) { |
384 views::View* top_container = browser_view_->top_container(); | 564 MoveMouse(browser_view_->top_container(), hovered); |
385 gfx::Point cursor_pos; | |
386 if (!hovered) { | |
387 int bottom_edge = top_container->bounds().bottom(); | |
388 cursor_pos = gfx::Point(0, bottom_edge + 100); | |
389 } | |
390 views::View::ConvertPointToScreen(top_container, &cursor_pos); | |
391 aura::Env::GetInstance()->set_last_mouse_location(cursor_pos); | |
392 | |
393 UpdateMouseRevealedLock(false); | 565 UpdateMouseRevealedLock(false); |
394 } | 566 } |
395 | 567 |
396 //////////////////////////////////////////////////////////////////////////////// | 568 //////////////////////////////////////////////////////////////////////////////// |
397 // private: | 569 // private: |
398 | 570 |
399 void ImmersiveModeControllerAsh::EnableWindowObservers(bool enable) { | 571 void ImmersiveModeControllerAsh::EnableWindowObservers(bool enable) { |
400 if (!native_window_) { | 572 if (!native_window_) { |
401 DCHECK(!enable) << "ImmersiveModeControllerAsh not initialized"; | 573 DCHECK(!enable) << "ImmersiveModeControllerAsh not initialized"; |
402 return; | 574 return; |
(...skipping 10 matching lines...) Expand all Loading... |
413 focus_manager->RemoveFocusChangeListener(this); | 585 focus_manager->RemoveFocusChangeListener(this); |
414 } | 586 } |
415 | 587 |
416 if (enable) | 588 if (enable) |
417 native_window_->AddPreTargetHandler(this); | 589 native_window_->AddPreTargetHandler(this); |
418 else | 590 else |
419 native_window_->RemovePreTargetHandler(this); | 591 native_window_->RemovePreTargetHandler(this); |
420 | 592 |
421 // The window observer adds and removes itself from the native window. | 593 // The window observer adds and removes itself from the native window. |
422 window_observer_.reset(enable ? new WindowObserver(this) : NULL); | 594 window_observer_.reset(enable ? new WindowObserver(this) : NULL); |
| 595 |
| 596 if (!enable) |
| 597 StopObservingImplicitAnimations(); |
423 } | 598 } |
424 | 599 |
425 void ImmersiveModeControllerAsh::UpdateMouseRevealedLock(bool maybe_drag) { | 600 void ImmersiveModeControllerAsh::UpdateMouseRevealedLock(bool maybe_drag) { |
426 if (!enabled_) | 601 if (!enabled_) |
427 return; | 602 return; |
428 | 603 |
429 // Hover cannot initiate a reveal when the top-of-window views are sliding | 604 // Hover cannot initiate a reveal when the top-of-window views are sliding |
430 // closed or are closed. (With the exception of hovering at y = 0 which is | 605 // closed or are closed. (With the exception of hovering at y = 0 which is |
431 // handled in OnMouseEvent() ). | 606 // handled in OnMouseEvent() ). |
432 if (reveal_state_ == SLIDING_CLOSED || reveal_state_ == CLOSED) | 607 if (reveal_state_ == SLIDING_CLOSED || reveal_state_ == CLOSED) |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
500 return 0; | 675 return 0; |
501 case ANIMATE_SLOW: | 676 case ANIMATE_SLOW: |
502 return kRevealSlowAnimationDurationMs; | 677 return kRevealSlowAnimationDurationMs; |
503 case ANIMATE_FAST: | 678 case ANIMATE_FAST: |
504 return kRevealFastAnimationDurationMs; | 679 return kRevealFastAnimationDurationMs; |
505 } | 680 } |
506 NOTREACHED(); | 681 NOTREACHED(); |
507 return 0; | 682 return 0; |
508 } | 683 } |
509 | 684 |
510 void ImmersiveModeControllerAsh::MaybeStartReveal() { | 685 void ImmersiveModeControllerAsh::MaybeStartReveal(Animate animate) { |
511 if (enabled_ && reveal_state_ != REVEALED) | 686 if (!enabled_) |
512 StartReveal(ANIMATE_FAST); | 687 return; |
513 } | |
514 | 688 |
515 void ImmersiveModeControllerAsh::StartReveal(Animate animate) { | 689 // Callers with ANIMATE_NO expect this function to synchronously reveal the |
516 if (reveal_state_ == CLOSED) { | 690 // top-of-window views. In particular, this property is used to terminate the |
517 reveal_state_ = SLIDING_OPEN; | 691 // reveal animation if an equivalent animation for the anchored widgets |
| 692 // cannot be created. |
| 693 if (reveal_state_ == REVEALED || |
| 694 (reveal_state_ == SLIDING_OPEN && animate != ANIMATE_NO)) { |
| 695 return; |
| 696 } |
| 697 |
| 698 RevealState previous_reveal_state = reveal_state_; |
| 699 reveal_state_ = SLIDING_OPEN; |
| 700 if (previous_reveal_state == CLOSED) { |
518 // Turn on layer painting so we can smoothly animate. | 701 // Turn on layer painting so we can smoothly animate. |
519 EnablePaintToLayer(true); | 702 EnablePaintToLayer(true); |
520 | 703 |
521 // Ensure window caption buttons are updated and the view bounds are | 704 // Ensure window caption buttons are updated and the view bounds are |
522 // computed at normal (non-immersive-style) size. | 705 // computed at normal (non-immersive-style) size. |
523 LayoutBrowserView(false); | 706 LayoutBrowserView(false); |
524 | 707 |
| 708 // Do not do any more processing if LayoutBrowserView() changed |
| 709 // |reveal_state_|. |
| 710 if (reveal_state_ != SLIDING_OPEN) |
| 711 return; |
| 712 |
525 if (animate != ANIMATE_NO) { | 713 if (animate != ANIMATE_NO) { |
526 // Now that we have a layer, move it to the initial offscreen position. | 714 // Now that we have a layer, move it to the initial offscreen position. |
527 ui::Layer* layer = browser_view_->top_container()->layer(); | 715 ui::Layer* layer = browser_view_->top_container()->layer(); |
528 gfx::Transform transform; | 716 gfx::Transform transform; |
529 transform.Translate(0, -layer->bounds().height() + kAnimationOffsetY); | 717 transform.Translate(0, -layer->bounds().height() + kAnimationOffsetY); |
530 layer->SetTransform(transform); | 718 layer->SetTransform(transform); |
| 719 |
| 720 typedef std::set<views::Widget*> WidgetSet; |
| 721 const WidgetSet& visible_widgets = |
| 722 anchored_widget_manager_->visible_anchored_widgets(); |
| 723 for (WidgetSet::const_iterator it = visible_widgets.begin(); |
| 724 it != visible_widgets.end(); ++it) { |
| 725 (*it)->GetNativeWindow()->SetTransform(transform); |
| 726 } |
531 } | 727 } |
532 // Slide in the reveal view. | |
533 AnimateSlideOpen(GetAnimationDuration(animate)); | |
534 } else if (reveal_state_ == SLIDING_CLOSED) { | |
535 reveal_state_ = SLIDING_OPEN; | |
536 // Reverse the animation. | |
537 AnimateSlideOpen(GetAnimationDuration(animate)); | |
538 } | 728 } |
| 729 // Slide in the reveal view. |
| 730 DoAnimation(gfx::Transform(), GetAnimationDuration(animate)); |
539 } | 731 } |
540 | 732 |
541 void ImmersiveModeControllerAsh::EnablePaintToLayer(bool enable) { | 733 void ImmersiveModeControllerAsh::EnablePaintToLayer(bool enable) { |
542 browser_view_->top_container()->SetPaintToLayer(enable); | 734 browser_view_->top_container()->SetPaintToLayer(enable); |
543 | 735 |
544 // Views software compositing is not fully layer aware. If the bookmark bar | 736 // Views software compositing is not fully layer aware. If the bookmark bar |
545 // is detached while the top container layer slides on or off the screen, | 737 // is detached while the top container layer slides on or off the screen, |
546 // the pixels that become exposed are the remnants of the last software | 738 // the pixels that become exposed are the remnants of the last software |
547 // composite of the BrowserView, not the freshly-exposed bookmark bar. | 739 // composite of the BrowserView, not the freshly-exposed bookmark bar. |
548 // Force the bookmark bar to paint to a layer so the views composite | 740 // Force the bookmark bar to paint to a layer so the views composite |
549 // properly. The infobar container does not need this treatment because | 741 // properly. The infobar container does not need this treatment because |
550 // BrowserView::PaintChildren() always draws it last when it is visible. | 742 // BrowserView::PaintChildren() always draws it last when it is visible. |
551 BookmarkBarView* bookmark_bar = browser_view_->bookmark_bar(); | 743 BookmarkBarView* bookmark_bar = browser_view_->bookmark_bar(); |
552 if (!bookmark_bar) | 744 if (!bookmark_bar) |
553 return; | 745 return; |
554 if (enable && bookmark_bar->IsDetached()) | 746 if (enable && bookmark_bar->IsDetached()) |
555 bookmark_bar->SetPaintToLayer(true); | 747 bookmark_bar->SetPaintToLayer(true); |
556 else | 748 else |
557 bookmark_bar->SetPaintToLayer(false); | 749 bookmark_bar->SetPaintToLayer(false); |
558 } | 750 } |
559 | 751 |
560 void ImmersiveModeControllerAsh::LayoutBrowserView(bool immersive_style) { | 752 void ImmersiveModeControllerAsh::LayoutBrowserView(bool immersive_style) { |
561 // Update the window caption buttons. | 753 // Update the window caption buttons. |
562 browser_view_->GetWidget()->non_client_view()->frame_view()-> | 754 browser_view_->GetWidget()->non_client_view()->frame_view()-> |
563 ResetWindowControls(); | 755 ResetWindowControls(); |
564 browser_view_->tabstrip()->SetImmersiveStyle(immersive_style); | 756 browser_view_->tabstrip()->SetImmersiveStyle(immersive_style); |
565 browser_view_->frame()->GetRootView()->Layout(); | 757 browser_view_->frame()->GetRootView()->Layout(); |
566 } | 758 } |
567 | 759 |
568 void ImmersiveModeControllerAsh::AnimateSlideOpen(int duration_ms) { | 760 void ImmersiveModeControllerAsh::OnSlideOpenAnimationCompleted() { |
569 ui::Layer* layer = browser_view_->top_container()->layer(); | 761 DCHECK_EQ(SLIDING_OPEN, reveal_state_); |
570 // Stop any slide closed animation in progress. | 762 reveal_state_ = REVEALED; |
571 layer->GetAnimator()->AbortAllAnimations(); | |
572 | 763 |
573 ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); | 764 // The user may not have moved the mouse since the reveal was initiated. |
574 settings.AddObserver(slide_open_observer_.get()); | 765 // Update the revealed lock to reflect the mouse's current state. |
575 settings.SetTweenType(ui::Tween::EASE_OUT); | 766 UpdateMouseRevealedLock(true); |
576 settings.SetTransitionDuration( | |
577 base::TimeDelta::FromMilliseconds(duration_ms)); | |
578 layer->SetTransform(gfx::Transform()); | |
579 } | 767 } |
580 | 768 |
581 void ImmersiveModeControllerAsh::OnSlideOpenAnimationCompleted() { | 769 void ImmersiveModeControllerAsh::MaybeEndReveal(Animate animate) { |
582 if (reveal_state_ == SLIDING_OPEN) { | 770 if (!enabled_ || revealed_lock_count_ != 0) |
583 reveal_state_ = REVEALED; | 771 return; |
584 | 772 |
585 // The user may not have moved the mouse since the reveal was initiated. | 773 // Callers with ANIMATE_NO expect this function to synchronously close the |
586 // Update the revealed lock to reflect the mouse's current state. | 774 // top-of-window views. |
587 UpdateMouseRevealedLock(true); | 775 if (reveal_state_ == CLOSED || |
| 776 (reveal_state_ == SLIDING_CLOSED && animate != ANIMATE_NO)) { |
| 777 return; |
| 778 } |
| 779 |
| 780 // Visible anchored widgets keep the top-of-window views revealed. |
| 781 DCHECK(anchored_widget_manager_->visible_anchored_widgets().empty()); |
| 782 |
| 783 reveal_state_ = SLIDING_CLOSED; |
| 784 int duration_ms = GetAnimationDuration(animate); |
| 785 if (duration_ms > 0) { |
| 786 // The bookmark bar may have become detached during the reveal so ensure |
| 787 // layers are available. This is a no-op for the top container. |
| 788 EnablePaintToLayer(true); |
| 789 |
| 790 ui::Layer* top_container_layer = browser_view_->top_container()->layer(); |
| 791 gfx::Transform target_transform; |
| 792 target_transform.Translate(0, |
| 793 -top_container_layer->bounds().height() + kAnimationOffsetY); |
| 794 |
| 795 DoAnimation(target_transform, duration_ms); |
| 796 } else { |
| 797 OnSlideClosedAnimationCompleted(); |
588 } | 798 } |
589 } | 799 } |
590 | 800 |
591 void ImmersiveModeControllerAsh::MaybeEndReveal(Animate animate) { | 801 void ImmersiveModeControllerAsh::OnSlideClosedAnimationCompleted() { |
592 if (enabled_ && reveal_state_ != CLOSED && revealed_lock_count_ == 0) | 802 DCHECK_EQ(SLIDING_CLOSED, reveal_state_); |
593 EndReveal(animate); | 803 reveal_state_ = CLOSED; |
| 804 // Layers aren't needed after animation completes. |
| 805 EnablePaintToLayer(false); |
| 806 // Update tabstrip for closed state. |
| 807 LayoutBrowserView(true); |
594 } | 808 } |
595 | 809 |
596 void ImmersiveModeControllerAsh::EndReveal(Animate animate) { | 810 void ImmersiveModeControllerAsh::DoAnimation( |
597 if (reveal_state_ == SLIDING_OPEN || reveal_state_ == REVEALED) { | 811 const gfx::Transform& target_transform, |
598 reveal_state_ = SLIDING_CLOSED; | 812 int duration_ms) { |
599 int duration_ms = GetAnimationDuration(animate); | 813 StopObservingImplicitAnimations(); |
600 if (duration_ms > 0) { | 814 DoLayerAnimation(browser_view_->top_container()->layer(), target_transform, |
601 // Bookmark bar have become detached during the reveal so ensure | 815 duration_ms, this); |
602 // layers are available. This is a no-op for top container. | 816 |
603 EnablePaintToLayer(true); | 817 typedef std::set<views::Widget*> WidgetSet; |
604 AnimateSlideClosed(duration_ms); | 818 const WidgetSet& visible_widgets = |
605 } else { | 819 anchored_widget_manager_->visible_anchored_widgets(); |
606 OnSlideClosedAnimationCompleted(); | 820 for (WidgetSet::const_iterator it = visible_widgets.begin(); |
607 } | 821 it != visible_widgets.end(); ++it) { |
| 822 // The anchored widget's bounds are set to the target bounds right when the |
| 823 // animation starts. The transform is used to animate the widget's position. |
| 824 // Using the target bounds allows us to "stay anchored" if other code |
| 825 // changes the widget bounds in the middle of the animation. (This is the |
| 826 // case if the fullscreen exit bubble type is changed during the immersive |
| 827 // reveal animation). |
| 828 DoLayerAnimation((*it)->GetNativeWindow()->layer(), gfx::Transform(), |
| 829 duration_ms, NULL); |
608 } | 830 } |
609 } | 831 } |
610 | 832 |
611 void ImmersiveModeControllerAsh::AnimateSlideClosed(int duration_ms) { | 833 void ImmersiveModeControllerAsh::DoLayerAnimation( |
612 // Stop any slide open animation in progress, but don't skip to the end. This | 834 ui::Layer* layer, |
613 // avoids a visual "pop" when starting a hide in the middle of a show. | 835 const gfx::Transform& target_transform, |
614 ui::Layer* layer = browser_view_->top_container()->layer(); | 836 int duration_ms, |
615 layer->GetAnimator()->AbortAllAnimations(); | 837 ui::ImplicitAnimationObserver* observer) { |
616 | |
617 ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); | 838 ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); |
618 settings.SetTweenType(ui::Tween::EASE_OUT); | 839 settings.SetTweenType(ui::Tween::EASE_OUT); |
619 settings.SetTransitionDuration( | 840 settings.SetTransitionDuration( |
620 base::TimeDelta::FromMilliseconds(duration_ms)); | 841 base::TimeDelta::FromMilliseconds(duration_ms)); |
621 settings.AddObserver(slide_closed_observer_.get()); | 842 settings.SetPreemptionStrategy( |
622 gfx::Transform transform; | 843 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
623 transform.Translate(0, -layer->bounds().height() + kAnimationOffsetY); | 844 if (observer) |
624 layer->SetTransform(transform); | 845 settings.AddObserver(observer); |
| 846 layer->SetTransform(target_transform); |
625 } | 847 } |
626 | |
627 void ImmersiveModeControllerAsh::OnSlideClosedAnimationCompleted() { | |
628 if (reveal_state_ == SLIDING_CLOSED) { | |
629 reveal_state_ = CLOSED; | |
630 // Layers aren't needed after animation completes. | |
631 EnablePaintToLayer(false); | |
632 // Update tabstrip for closed state. | |
633 LayoutBrowserView(true); | |
634 } | |
635 } | |
OLD | NEW |