Add a qcms_profile_get_description() api
[chromium-blink-merge.git] / ash / shelf / shelf_layout_manager.cc
blob08831e24dfb194a5692e01d817225290c311725f
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/shelf/shelf_layout_manager.h"
7 #include <algorithm>
8 #include <cmath>
9 #include <cstring>
10 #include <string>
11 #include <vector>
13 #include "ash/accelerators/accelerator_commands.h"
14 #include "ash/ash_switches.h"
15 #include "ash/root_window_controller.h"
16 #include "ash/screen_util.h"
17 #include "ash/session/session_state_delegate.h"
18 #include "ash/shelf/shelf.h"
19 #include "ash/shelf/shelf_bezel_event_filter.h"
20 #include "ash/shelf/shelf_constants.h"
21 #include "ash/shelf/shelf_layout_manager_observer.h"
22 #include "ash/shelf/shelf_widget.h"
23 #include "ash/shell.h"
24 #include "ash/shell_window_ids.h"
25 #include "ash/system/status_area_widget.h"
26 #include "ash/wm/gestures/shelf_gesture_handler.h"
27 #include "ash/wm/lock_state_controller.h"
28 #include "ash/wm/mru_window_tracker.h"
29 #include "ash/wm/window_animations.h"
30 #include "ash/wm/window_state.h"
31 #include "ash/wm/window_util.h"
32 #include "ash/wm/workspace_controller.h"
33 #include "base/auto_reset.h"
34 #include "base/command_line.h"
35 #include "base/command_line.h"
36 #include "base/i18n/rtl.h"
37 #include "base/strings/string_number_conversions.h"
38 #include "base/strings/string_util.h"
39 #include "ui/aura/client/cursor_client.h"
40 #include "ui/aura/window_event_dispatcher.h"
41 #include "ui/base/ui_base_switches.h"
42 #include "ui/compositor/layer.h"
43 #include "ui/compositor/layer_animation_observer.h"
44 #include "ui/compositor/layer_animator.h"
45 #include "ui/compositor/scoped_layer_animation_settings.h"
46 #include "ui/events/event.h"
47 #include "ui/events/event_handler.h"
48 #include "ui/gfx/screen.h"
49 #include "ui/keyboard/keyboard_util.h"
50 #include "ui/views/widget/widget.h"
51 #include "ui/wm/public/activation_client.h"
53 namespace ash {
54 namespace {
56 // Delay before showing the shelf. This is after the mouse stops moving.
57 const int kAutoHideDelayMS = 200;
59 // To avoid hiding the shelf when the mouse transitions from a message bubble
60 // into the shelf, the hit test area is enlarged by this amount of pixels to
61 // keep the shelf from hiding.
62 const int kNotificationBubbleGapHeight = 6;
64 // The maximum size of the region on the display opposing the shelf managed by
65 // this ShelfLayoutManager which can trigger showing the shelf.
66 // For instance:
67 // - Primary display is left of secondary display.
68 // - Shelf is left aligned
69 // - This ShelfLayoutManager manages the shelf for the secondary display.
70 // |kMaxAutoHideShowShelfRegionSize| refers to the maximum size of the region
71 // from the right edge of the primary display which can trigger showing the
72 // auto hidden shelf. The region is used to make it easier to trigger showing
73 // the auto hidden shelf when the shelf is on the boundary between displays.
74 const int kMaxAutoHideShowShelfRegionSize = 10;
76 ui::Layer* GetLayer(views::Widget* widget) {
77 return widget->GetNativeView()->layer();
80 bool IsDraggingTrayEnabled() {
81 static bool dragging_tray_allowed = base::CommandLine::ForCurrentProcess()->
82 HasSwitch(ash::switches::kAshEnableTrayDragging);
83 return dragging_tray_allowed;
86 } // namespace
88 // static
89 const int ShelfLayoutManager::kWorkspaceAreaVisibleInset = 2;
91 // static
92 const int ShelfLayoutManager::kWorkspaceAreaAutoHideInset = 5;
94 // static
95 const int ShelfLayoutManager::kAutoHideSize = 3;
97 // static
98 const int ShelfLayoutManager::kShelfItemInset = 3;
100 // ShelfLayoutManager::AutoHideEventFilter -------------------------------------
102 // Notifies ShelfLayoutManager any time the mouse moves.
103 class ShelfLayoutManager::AutoHideEventFilter : public ui::EventHandler {
104 public:
105 explicit AutoHideEventFilter(ShelfLayoutManager* shelf);
106 ~AutoHideEventFilter() override;
108 // Returns true if the last mouse event was a mouse drag.
109 bool in_mouse_drag() const { return in_mouse_drag_; }
111 // Overridden from ui::EventHandler:
112 void OnMouseEvent(ui::MouseEvent* event) override;
113 void OnGestureEvent(ui::GestureEvent* event) override;
115 private:
116 ShelfLayoutManager* shelf_;
117 bool in_mouse_drag_;
118 ShelfGestureHandler gesture_handler_;
119 DISALLOW_COPY_AND_ASSIGN(AutoHideEventFilter);
122 ShelfLayoutManager::AutoHideEventFilter::AutoHideEventFilter(
123 ShelfLayoutManager* shelf)
124 : shelf_(shelf),
125 in_mouse_drag_(false) {
126 Shell::GetInstance()->AddPreTargetHandler(this);
129 ShelfLayoutManager::AutoHideEventFilter::~AutoHideEventFilter() {
130 Shell::GetInstance()->RemovePreTargetHandler(this);
133 void ShelfLayoutManager::AutoHideEventFilter::OnMouseEvent(
134 ui::MouseEvent* event) {
135 // This also checks IsShelfWindow() to make sure we don't attempt to hide the
136 // shelf if the mouse down occurs on the shelf.
137 in_mouse_drag_ = (event->type() == ui::ET_MOUSE_DRAGGED ||
138 (in_mouse_drag_ && event->type() != ui::ET_MOUSE_RELEASED &&
139 event->type() != ui::ET_MOUSE_CAPTURE_CHANGED)) &&
140 !shelf_->IsShelfWindow(static_cast<aura::Window*>(event->target()));
141 if (event->type() == ui::ET_MOUSE_MOVED)
142 shelf_->UpdateAutoHideState();
143 return;
146 void ShelfLayoutManager::AutoHideEventFilter::OnGestureEvent(
147 ui::GestureEvent* event) {
148 if (shelf_->IsShelfWindow(static_cast<aura::Window*>(event->target()))) {
149 if (gesture_handler_.ProcessGestureEvent(*event))
150 event->StopPropagation();
154 // ShelfLayoutManager:UpdateShelfObserver --------------------------------------
156 // UpdateShelfObserver is used to delay updating the background until the
157 // animation completes.
158 class ShelfLayoutManager::UpdateShelfObserver
159 : public ui::ImplicitAnimationObserver {
160 public:
161 explicit UpdateShelfObserver(ShelfLayoutManager* shelf) : shelf_(shelf) {
162 shelf_->update_shelf_observer_ = this;
165 void Detach() {
166 shelf_ = NULL;
169 void OnImplicitAnimationsCompleted() override {
170 if (shelf_)
171 shelf_->UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE);
172 delete this;
175 private:
176 ~UpdateShelfObserver() override {
177 if (shelf_)
178 shelf_->update_shelf_observer_ = NULL;
181 // Shelf we're in. NULL if deleted before we're deleted.
182 ShelfLayoutManager* shelf_;
184 DISALLOW_COPY_AND_ASSIGN(UpdateShelfObserver);
187 // ShelfLayoutManager ----------------------------------------------------------
189 ShelfLayoutManager::ShelfLayoutManager(ShelfWidget* shelf)
190 : SnapToPixelLayoutManager(shelf->GetNativeView()->parent()),
191 root_window_(shelf->GetNativeView()->GetRootWindow()),
192 updating_bounds_(false),
193 auto_hide_behavior_(SHELF_AUTO_HIDE_BEHAVIOR_NEVER),
194 alignment_(SHELF_ALIGNMENT_BOTTOM),
195 shelf_(shelf),
196 workspace_controller_(NULL),
197 window_overlaps_shelf_(false),
198 mouse_over_shelf_when_auto_hide_timer_started_(false),
199 bezel_event_filter_(new ShelfBezelEventFilter(this)),
200 gesture_drag_status_(GESTURE_DRAG_NONE),
201 gesture_drag_amount_(0.f),
202 gesture_drag_auto_hide_state_(SHELF_AUTO_HIDE_SHOWN),
203 update_shelf_observer_(NULL),
204 duration_override_in_ms_(0) {
205 Shell::GetInstance()->AddShellObserver(this);
206 Shell::GetInstance()->lock_state_controller()->AddObserver(this);
207 aura::client::GetActivationClient(root_window_)->AddObserver(this);
208 Shell::GetInstance()->session_state_delegate()->AddSessionStateObserver(this);
211 ShelfLayoutManager::~ShelfLayoutManager() {
212 if (update_shelf_observer_)
213 update_shelf_observer_->Detach();
215 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_, WillDeleteShelf());
216 Shell::GetInstance()->RemoveShellObserver(this);
217 Shell::GetInstance()->lock_state_controller()->RemoveObserver(this);
218 aura::client::GetActivationClient(root_window_)->RemoveObserver(this);
219 Shell::GetInstance()->
220 session_state_delegate()->RemoveSessionStateObserver(this);
223 void ShelfLayoutManager::SetAutoHideBehavior(ShelfAutoHideBehavior behavior) {
224 if (auto_hide_behavior_ == behavior)
225 return;
226 auto_hide_behavior_ = behavior;
227 UpdateVisibilityState();
228 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
229 OnAutoHideBehaviorChanged(root_window_,
230 auto_hide_behavior_));
233 void ShelfLayoutManager::PrepareForShutdown() {
234 // Clear all event filters, otherwise sometimes those filters may catch
235 // synthesized mouse event and cause crashes during the shutdown.
236 set_workspace_controller(NULL);
237 auto_hide_event_filter_.reset();
238 bezel_event_filter_.reset();
241 bool ShelfLayoutManager::IsVisible() const {
242 // status_area_widget() may be NULL during the shutdown.
243 return shelf_->status_area_widget() &&
244 shelf_->status_area_widget()->IsVisible() &&
245 (state_.visibility_state == SHELF_VISIBLE ||
246 (state_.visibility_state == SHELF_AUTO_HIDE &&
247 state_.auto_hide_state == SHELF_AUTO_HIDE_SHOWN));
250 bool ShelfLayoutManager::SetAlignment(ShelfAlignment alignment) {
251 if (alignment_ == alignment)
252 return false;
254 alignment_ = alignment;
255 if (state_.is_screen_locked || state_.is_adding_user_screen) {
256 // The shelf will itself move to the bottom while locked. If a request is
257 // sent to move while being locked, we postpone the move until the lock
258 // screen goes away.
259 return false;
262 // This should not be called during the lock screen transitions.
263 shelf_->SetAlignment(alignment);
264 LayoutShelf();
265 return true;
268 ShelfAlignment ShelfLayoutManager::GetAlignment() const {
269 // When the screen is locked or a user gets added, the shelf is forced into
270 // bottom alignment. Note: We cannot use state_.is_screen_locked here since
271 // that flag gets set later than the SessionStateDelegate reports a locked
272 // screen which leads in
273 if (state_.is_screen_locked || state_.is_adding_user_screen)
274 return SHELF_ALIGNMENT_BOTTOM;
275 return alignment_;
278 gfx::Rect ShelfLayoutManager::GetIdealBounds() {
279 gfx::Rect bounds(
280 ScreenUtil::GetDisplayBoundsInParent(shelf_->GetNativeView()));
281 int width = 0, height = 0;
282 GetShelfSize(&width, &height);
283 return SelectValueForShelfAlignment(
284 gfx::Rect(bounds.x(), bounds.bottom() - height, bounds.width(), height),
285 gfx::Rect(bounds.x(), bounds.y(), width, bounds.height()),
286 gfx::Rect(bounds.right() - width, bounds.y(), width, bounds.height()),
287 gfx::Rect(bounds.x(), bounds.y(), bounds.width(), height));
290 void ShelfLayoutManager::LayoutShelf() {
291 TargetBounds target_bounds;
292 CalculateTargetBounds(state_, &target_bounds);
293 UpdateBoundsAndOpacity(target_bounds, false, NULL);
295 if (shelf_->shelf()) {
296 // This is not part of UpdateBoundsAndOpacity() because
297 // SetShelfViewBounds() sets the bounds immediately and does not animate.
298 // The height of the ShelfView for a horizontal shelf and the width of
299 // the ShelfView for a vertical shelf are set when |shelf_|'s bounds
300 // are changed via UpdateBoundsAndOpacity(). This sets the origin and the
301 // dimension in the other direction.
302 shelf_->shelf()->SetShelfViewBounds(
303 target_bounds.shelf_bounds_in_shelf);
307 ShelfVisibilityState ShelfLayoutManager::CalculateShelfVisibility() {
308 switch(auto_hide_behavior_) {
309 case SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS:
310 return SHELF_AUTO_HIDE;
311 case SHELF_AUTO_HIDE_BEHAVIOR_NEVER:
312 return SHELF_VISIBLE;
313 case SHELF_AUTO_HIDE_ALWAYS_HIDDEN:
314 return SHELF_HIDDEN;
316 return SHELF_VISIBLE;
319 void ShelfLayoutManager::UpdateVisibilityState() {
320 // Bail out early when there is no |workspace_controller_|, which happens
321 // during shutdown after PrepareForShutdown.
322 if (!workspace_controller_)
323 return;
325 if (state_.is_screen_locked || state_.is_adding_user_screen) {
326 SetState(SHELF_VISIBLE);
327 } else {
328 // TODO(zelidrag): Verify shelf drag animation still shows on the device
329 // when we are in SHELF_AUTO_HIDE_ALWAYS_HIDDEN.
330 WorkspaceWindowState window_state(workspace_controller_->GetWindowState());
331 switch (window_state) {
332 case WORKSPACE_WINDOW_STATE_FULL_SCREEN: {
333 const aura::Window* fullscreen_window = GetRootWindowController(
334 root_window_)->GetWindowForFullscreenMode();
335 if (fullscreen_window && wm::GetWindowState(fullscreen_window)->
336 hide_shelf_when_fullscreen()) {
337 SetState(SHELF_HIDDEN);
338 } else {
339 // The shelf is sometimes not hidden when in immersive fullscreen.
340 // Force the shelf to be auto hidden in this case.
341 SetState(SHELF_AUTO_HIDE);
343 break;
346 case WORKSPACE_WINDOW_STATE_MAXIMIZED:
347 SetState(CalculateShelfVisibility());
348 break;
350 case WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF:
351 case WORKSPACE_WINDOW_STATE_DEFAULT:
352 SetState(CalculateShelfVisibility());
353 SetWindowOverlapsShelf(window_state ==
354 WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF);
355 break;
360 void ShelfLayoutManager::UpdateAutoHideState() {
361 ShelfAutoHideState auto_hide_state =
362 CalculateAutoHideState(state_.visibility_state);
363 if (auto_hide_state != state_.auto_hide_state) {
364 if (auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) {
365 // Hides happen immediately.
366 SetState(state_.visibility_state);
367 } else {
368 if (!auto_hide_timer_.IsRunning()) {
369 mouse_over_shelf_when_auto_hide_timer_started_ =
370 shelf_->GetWindowBoundsInScreen().Contains(
371 Shell::GetScreen()->GetCursorScreenPoint());
373 auto_hide_timer_.Start(
374 FROM_HERE,
375 base::TimeDelta::FromMilliseconds(kAutoHideDelayMS),
376 this, &ShelfLayoutManager::UpdateAutoHideStateNow);
378 } else {
379 StopAutoHideTimer();
383 void ShelfLayoutManager::SetWindowOverlapsShelf(bool value) {
384 window_overlaps_shelf_ = value;
385 UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE);
388 void ShelfLayoutManager::AddObserver(ShelfLayoutManagerObserver* observer) {
389 observers_.AddObserver(observer);
392 void ShelfLayoutManager::RemoveObserver(ShelfLayoutManagerObserver* observer) {
393 observers_.RemoveObserver(observer);
396 ////////////////////////////////////////////////////////////////////////////////
397 // ShelfLayoutManager, Gesture functions:
399 void ShelfLayoutManager::OnGestureEdgeSwipe(const ui::GestureEvent& gesture) {
400 if (visibility_state() == SHELF_AUTO_HIDE) {
401 gesture_drag_auto_hide_state_ = SHELF_AUTO_HIDE_SHOWN;
402 gesture_drag_status_ = GESTURE_DRAG_COMPLETE_IN_PROGRESS;
403 UpdateVisibilityState();
404 gesture_drag_status_ = GESTURE_DRAG_NONE;
408 void ShelfLayoutManager::StartGestureDrag(const ui::GestureEvent& gesture) {
409 gesture_drag_status_ = GESTURE_DRAG_IN_PROGRESS;
410 gesture_drag_amount_ = 0.f;
411 gesture_drag_auto_hide_state_ = visibility_state() == SHELF_AUTO_HIDE ?
412 auto_hide_state() : SHELF_AUTO_HIDE_SHOWN;
413 UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE);
416 ShelfLayoutManager::DragState ShelfLayoutManager::UpdateGestureDrag(
417 const ui::GestureEvent& gesture) {
418 bool horizontal = IsHorizontalAlignment();
419 gesture_drag_amount_ += horizontal ? gesture.details().scroll_y() :
420 gesture.details().scroll_x();
421 LayoutShelf();
423 // Start reveling the status menu when:
424 // - dragging up on an already visible shelf
425 // - dragging up on a hidden shelf, but it is currently completely visible.
426 if (horizontal && gesture.details().scroll_y() < 0) {
427 int min_height = 0;
428 if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_HIDDEN && shelf_)
429 min_height = shelf_->GetContentsView()->GetPreferredSize().height();
431 if (min_height < shelf_->GetWindowBoundsInScreen().height() &&
432 gesture.root_location().x() >=
433 shelf_->status_area_widget()->GetWindowBoundsInScreen().x() &&
434 IsDraggingTrayEnabled())
435 return DRAG_TRAY;
438 return DRAG_SHELF;
441 void ShelfLayoutManager::CompleteGestureDrag(const ui::GestureEvent& gesture) {
442 bool horizontal = IsHorizontalAlignment();
443 bool should_change = false;
444 if (gesture.type() == ui::ET_GESTURE_SCROLL_END) {
445 // The visibility of the shelf changes only if the shelf was dragged X%
446 // along the correct axis. If the shelf was already visible, then the
447 // direction of the drag does not matter.
448 const float kDragHideThreshold = 0.4f;
449 gfx::Rect bounds = GetIdealBounds();
450 float drag_ratio = fabs(gesture_drag_amount_) /
451 (horizontal ? bounds.height() : bounds.width());
452 if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN) {
453 should_change = drag_ratio > kDragHideThreshold;
454 } else {
455 bool correct_direction = false;
456 switch (GetAlignment()) {
457 case SHELF_ALIGNMENT_BOTTOM:
458 case SHELF_ALIGNMENT_RIGHT:
459 correct_direction = gesture_drag_amount_ < 0;
460 break;
461 case SHELF_ALIGNMENT_LEFT:
462 case SHELF_ALIGNMENT_TOP:
463 correct_direction = gesture_drag_amount_ > 0;
464 break;
466 should_change = correct_direction && drag_ratio > kDragHideThreshold;
468 } else if (gesture.type() == ui::ET_SCROLL_FLING_START) {
469 if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN) {
470 should_change = horizontal ? fabs(gesture.details().velocity_y()) > 0 :
471 fabs(gesture.details().velocity_x()) > 0;
472 } else {
473 should_change = SelectValueForShelfAlignment(
474 gesture.details().velocity_y() < 0,
475 gesture.details().velocity_x() > 0,
476 gesture.details().velocity_x() < 0,
477 gesture.details().velocity_y() > 0);
479 } else {
480 NOTREACHED();
483 if (!should_change) {
484 CancelGestureDrag();
485 return;
487 if (shelf_) {
488 shelf_->Deactivate();
489 shelf_->status_area_widget()->Deactivate();
491 gesture_drag_auto_hide_state_ =
492 gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN ?
493 SHELF_AUTO_HIDE_HIDDEN : SHELF_AUTO_HIDE_SHOWN;
494 ShelfAutoHideBehavior new_auto_hide_behavior =
495 gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN ?
496 SHELF_AUTO_HIDE_BEHAVIOR_NEVER : SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS;
498 // When in fullscreen and the shelf is forced to be auto hidden, the auto hide
499 // behavior affects neither the visibility state nor the auto hide state. Set
500 // |gesture_drag_status_| to GESTURE_DRAG_COMPLETE_IN_PROGRESS to set the auto
501 // hide state to |gesture_drag_auto_hide_state_|.
502 gesture_drag_status_ = GESTURE_DRAG_COMPLETE_IN_PROGRESS;
503 if (auto_hide_behavior_ != new_auto_hide_behavior)
504 SetAutoHideBehavior(new_auto_hide_behavior);
505 else
506 UpdateVisibilityState();
507 gesture_drag_status_ = GESTURE_DRAG_NONE;
510 void ShelfLayoutManager::CancelGestureDrag() {
511 gesture_drag_status_ = GESTURE_DRAG_CANCEL_IN_PROGRESS;
512 UpdateVisibilityState();
513 gesture_drag_status_ = GESTURE_DRAG_NONE;
516 void ShelfLayoutManager::SetAnimationDurationOverride(
517 int duration_override_in_ms) {
518 duration_override_in_ms_ = duration_override_in_ms;
521 ////////////////////////////////////////////////////////////////////////////////
522 // ShelfLayoutManager, aura::LayoutManager implementation:
524 void ShelfLayoutManager::OnWindowResized() {
525 LayoutShelf();
528 void ShelfLayoutManager::SetChildBounds(aura::Window* child,
529 const gfx::Rect& requested_bounds) {
530 SnapToPixelLayoutManager::SetChildBounds(child, requested_bounds);
531 // We may contain other widgets (such as frame maximize bubble) but they don't
532 // effect the layout in anyway.
533 if (!updating_bounds_ &&
534 ((shelf_->GetNativeView() == child) ||
535 (shelf_->status_area_widget()->GetNativeView() == child))) {
536 LayoutShelf();
540 void ShelfLayoutManager::OnLockStateChanged(bool locked) {
541 // Force the shelf to layout for alignment (bottom if locked, restore
542 // the previous alignment otherwise).
543 state_.is_screen_locked = locked;
544 UpdateShelfVisibilityAfterLoginUIChange();
547 void ShelfLayoutManager::OnWindowActivated(aura::Window* gained_active,
548 aura::Window* lost_active) {
549 UpdateAutoHideStateNow();
552 bool ShelfLayoutManager::IsHorizontalAlignment() const {
553 return GetAlignment() == SHELF_ALIGNMENT_BOTTOM ||
554 GetAlignment() == SHELF_ALIGNMENT_TOP;
557 // static
558 ShelfLayoutManager* ShelfLayoutManager::ForShelf(aura::Window* window) {
559 ShelfWidget* shelf = RootWindowController::ForShelf(window)->shelf();
560 return shelf ? shelf->shelf_layout_manager() : NULL;
563 ////////////////////////////////////////////////////////////////////////////////
564 // ShelfLayoutManager, private:
566 ShelfLayoutManager::TargetBounds::TargetBounds() : opacity(0.0f) {}
567 ShelfLayoutManager::TargetBounds::~TargetBounds() {}
569 void ShelfLayoutManager::SetState(ShelfVisibilityState visibility_state) {
570 if (!shelf_->GetNativeView())
571 return;
573 State state;
574 state.visibility_state = visibility_state;
575 state.auto_hide_state = CalculateAutoHideState(visibility_state);
576 state.window_state = workspace_controller_ ?
577 workspace_controller_->GetWindowState() : WORKSPACE_WINDOW_STATE_DEFAULT;
578 // Preserve the log in screen states.
579 state.is_adding_user_screen = state_.is_adding_user_screen;
580 state.is_screen_locked = state_.is_screen_locked;
582 // Force an update because gesture drags affect the shelf bounds and we
583 // should animate back to the normal bounds at the end of a gesture.
584 bool force_update =
585 (gesture_drag_status_ == GESTURE_DRAG_CANCEL_IN_PROGRESS ||
586 gesture_drag_status_ == GESTURE_DRAG_COMPLETE_IN_PROGRESS);
588 if (!force_update && state_.Equals(state))
589 return; // Nothing changed.
591 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
592 WillChangeVisibilityState(visibility_state));
594 if (state.visibility_state == SHELF_AUTO_HIDE) {
595 // When state is SHELF_AUTO_HIDE we need to track when the mouse is over the
596 // shelf to unhide it. AutoHideEventFilter does that for us.
597 if (!auto_hide_event_filter_)
598 auto_hide_event_filter_.reset(new AutoHideEventFilter(this));
599 } else {
600 auto_hide_event_filter_.reset(NULL);
603 StopAutoHideTimer();
605 State old_state = state_;
606 state_ = state;
608 BackgroundAnimatorChangeType change_type = BACKGROUND_CHANGE_ANIMATE;
609 bool delay_background_change = false;
611 // Do not animate the background when:
612 // - Going from a hidden / auto hidden shelf in fullscreen to a visible shelf
613 // in maximized mode.
614 // - Going from an auto hidden shelf in maximized mode to a visible shelf in
615 // maximized mode.
616 if (state.visibility_state == SHELF_VISIBLE &&
617 state.window_state == WORKSPACE_WINDOW_STATE_MAXIMIZED &&
618 old_state.visibility_state != SHELF_VISIBLE) {
619 change_type = BACKGROUND_CHANGE_IMMEDIATE;
620 } else {
621 // Delay the animation when the shelf was hidden, and has just been made
622 // visible (e.g. using a gesture-drag).
623 if (state.visibility_state == SHELF_VISIBLE &&
624 old_state.visibility_state == SHELF_AUTO_HIDE &&
625 old_state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) {
626 delay_background_change = true;
630 if (delay_background_change) {
631 if (update_shelf_observer_)
632 update_shelf_observer_->Detach();
633 // UpdateShelfBackground deletes itself when the animation is done.
634 update_shelf_observer_ = new UpdateShelfObserver(this);
635 } else {
636 UpdateShelfBackground(change_type);
639 shelf_->SetDimsShelf(
640 state.visibility_state == SHELF_VISIBLE &&
641 state.window_state == WORKSPACE_WINDOW_STATE_MAXIMIZED);
643 TargetBounds target_bounds;
644 CalculateTargetBounds(state_, &target_bounds);
645 UpdateBoundsAndOpacity(target_bounds, true,
646 delay_background_change ? update_shelf_observer_ : NULL);
648 // OnAutoHideStateChanged Should be emitted when:
649 // - firstly state changed to auto-hide from other state
650 // - or, auto_hide_state has changed
651 if ((old_state.visibility_state != state_.visibility_state &&
652 state_.visibility_state == SHELF_AUTO_HIDE) ||
653 old_state.auto_hide_state != state_.auto_hide_state) {
654 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
655 OnAutoHideStateChanged(state_.auto_hide_state));
659 void ShelfLayoutManager::UpdateBoundsAndOpacity(
660 const TargetBounds& target_bounds,
661 bool animate,
662 ui::ImplicitAnimationObserver* observer) {
663 base::AutoReset<bool> auto_reset_updating_bounds(&updating_bounds_, true);
665 ui::ScopedLayerAnimationSettings shelf_animation_setter(
666 GetLayer(shelf_)->GetAnimator());
667 ui::ScopedLayerAnimationSettings status_animation_setter(
668 GetLayer(shelf_->status_area_widget())->GetAnimator());
669 if (animate) {
670 int duration = duration_override_in_ms_ ? duration_override_in_ms_ :
671 kCrossFadeDurationMS;
672 shelf_animation_setter.SetTransitionDuration(
673 base::TimeDelta::FromMilliseconds(duration));
674 shelf_animation_setter.SetTweenType(gfx::Tween::EASE_OUT);
675 shelf_animation_setter.SetPreemptionStrategy(
676 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
677 status_animation_setter.SetTransitionDuration(
678 base::TimeDelta::FromMilliseconds(duration));
679 status_animation_setter.SetTweenType(gfx::Tween::EASE_OUT);
680 status_animation_setter.SetPreemptionStrategy(
681 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
682 } else {
683 StopAnimating();
684 shelf_animation_setter.SetTransitionDuration(base::TimeDelta());
685 status_animation_setter.SetTransitionDuration(base::TimeDelta());
687 if (observer)
688 status_animation_setter.AddObserver(observer);
690 GetLayer(shelf_)->SetOpacity(target_bounds.opacity);
691 shelf_->SetBounds(ScreenUtil::ConvertRectToScreen(
692 shelf_->GetNativeView()->parent(),
693 target_bounds.shelf_bounds_in_root));
695 GetLayer(shelf_->status_area_widget())->SetOpacity(
696 target_bounds.status_opacity);
698 // Having a window which is visible but does not have an opacity is an
699 // illegal state. We therefore hide the shelf here if required.
700 if (!target_bounds.status_opacity)
701 shelf_->status_area_widget()->Hide();
702 // Setting visibility during an animation causes the visibility property to
703 // animate. Override the animation settings to immediately set the
704 // visibility property. Opacity will still animate.
706 // TODO(harrym): Once status area widget is a child view of shelf
707 // this can be simplified.
708 gfx::Rect status_bounds = target_bounds.status_bounds_in_shelf;
709 status_bounds.set_x(status_bounds.x() +
710 target_bounds.shelf_bounds_in_root.x());
711 status_bounds.set_y(status_bounds.y() +
712 target_bounds.shelf_bounds_in_root.y());
713 shelf_->status_area_widget()->SetBounds(
714 ScreenUtil::ConvertRectToScreen(
715 shelf_->status_area_widget()->GetNativeView()->parent(),
716 status_bounds));
717 if (!state_.is_screen_locked) {
718 gfx::Insets insets;
719 // If user session is blocked (login to new user session or add user to
720 // the existing session - multi-profile) then give 100% of work area only
721 // if keyboard is not shown.
722 if (!state_.is_adding_user_screen || !keyboard_bounds_.IsEmpty()) {
723 insets = target_bounds.work_area_insets;
725 Shell::GetInstance()->SetDisplayWorkAreaInsets(root_window_, insets);
729 // Setting visibility during an animation causes the visibility property to
730 // animate. Set the visibility property without an animation.
731 if (target_bounds.status_opacity)
732 shelf_->status_area_widget()->Show();
735 void ShelfLayoutManager::StopAnimating() {
736 GetLayer(shelf_)->GetAnimator()->StopAnimating();
737 GetLayer(shelf_->status_area_widget())->GetAnimator()->StopAnimating();
740 void ShelfLayoutManager::GetShelfSize(int* width, int* height) {
741 *width = *height = 0;
742 gfx::Size status_size(
743 shelf_->status_area_widget()->GetWindowBoundsInScreen().size());
744 if (IsHorizontalAlignment())
745 *height = kShelfSize;
746 else
747 *width = kShelfSize;
750 void ShelfLayoutManager::AdjustBoundsBasedOnAlignment(int inset,
751 gfx::Rect* bounds) const {
752 bounds->Inset(SelectValueForShelfAlignment(
753 gfx::Insets(0, 0, inset, 0),
754 gfx::Insets(0, inset, 0, 0),
755 gfx::Insets(0, 0, 0, inset),
756 gfx::Insets(inset, 0, 0, 0)));
759 void ShelfLayoutManager::CalculateTargetBounds(
760 const State& state,
761 TargetBounds* target_bounds) {
762 const gfx::Rect available_bounds(root_window_->bounds());
763 gfx::Rect status_size(
764 shelf_->status_area_widget()->GetWindowBoundsInScreen().size());
765 int shelf_width = 0, shelf_height = 0;
766 GetShelfSize(&shelf_width, &shelf_height);
767 if (IsHorizontalAlignment())
768 shelf_width = available_bounds.width();
769 else
770 shelf_height = available_bounds.height();
772 if (state.visibility_state == SHELF_AUTO_HIDE &&
773 state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) {
774 // Auto-hidden shelf always starts with the default size. If a gesture-drag
775 // is in progress, then the call to UpdateTargetBoundsForGesture() below
776 // takes care of setting the height properly.
777 if (IsHorizontalAlignment())
778 shelf_height = kAutoHideSize;
779 else
780 shelf_width = kAutoHideSize;
781 } else if (state.visibility_state == SHELF_HIDDEN ||
782 (!keyboard_bounds_.IsEmpty() && !keyboard::IsKeyboardOverscrollEnabled()))
784 if (IsHorizontalAlignment())
785 shelf_height = 0;
786 else
787 shelf_width = 0;
790 int bottom_shelf_vertical_offset = available_bounds.bottom();
791 if (keyboard_bounds_.IsEmpty())
792 bottom_shelf_vertical_offset -= shelf_height;
793 else
794 bottom_shelf_vertical_offset -= keyboard_bounds_.height();
796 target_bounds->shelf_bounds_in_root = SelectValueForShelfAlignment(
797 gfx::Rect(available_bounds.x(), bottom_shelf_vertical_offset,
798 available_bounds.width(), shelf_height),
799 gfx::Rect(available_bounds.x(), available_bounds.y(),
800 shelf_width, available_bounds.height()),
801 gfx::Rect(available_bounds.right() - shelf_width, available_bounds.y(),
802 shelf_width, available_bounds.height()),
803 gfx::Rect(available_bounds.x(), available_bounds.y(),
804 available_bounds.width(), shelf_height));
806 if (IsHorizontalAlignment())
807 status_size.set_height(kShelfSize);
808 else
809 status_size.set_width(kShelfSize);
811 target_bounds->status_bounds_in_shelf = SelectValueForShelfAlignment(
812 gfx::Rect(base::i18n::IsRTL() ? 0 : shelf_width - status_size.width(),
813 0, status_size.width(), status_size.height()),
814 gfx::Rect(shelf_width - status_size.width(),
815 shelf_height - status_size.height(), status_size.width(),
816 status_size.height()),
817 gfx::Rect(0, shelf_height - status_size.height(),
818 status_size.width(), status_size.height()),
819 gfx::Rect(base::i18n::IsRTL() ? 0 : shelf_width - status_size.width(),
820 shelf_height - status_size.height(),
821 status_size.width(), status_size.height()));
823 target_bounds->work_area_insets = SelectValueForShelfAlignment(
824 gfx::Insets(0, 0, GetWorkAreaSize(state, shelf_height), 0),
825 gfx::Insets(0, GetWorkAreaSize(state, shelf_width), 0, 0),
826 gfx::Insets(0, 0, 0, GetWorkAreaSize(state, shelf_width)),
827 gfx::Insets(GetWorkAreaSize(state, shelf_height), 0, 0, 0));
829 // TODO(varkha): The functionality of managing insets for display areas
830 // should probably be pushed to a separate component. This would simplify or
831 // remove entirely the dependency on keyboard and dock.
833 if (!keyboard_bounds_.IsEmpty() && !keyboard::IsKeyboardOverscrollEnabled()) {
834 // Also push in the work area inset for the keyboard if it is visible.
835 gfx::Insets keyboard_insets(0, 0, keyboard_bounds_.height(), 0);
836 target_bounds->work_area_insets += keyboard_insets;
839 // Also push in the work area inset for the dock if it is visible.
840 if (!dock_bounds_.IsEmpty()) {
841 gfx::Insets dock_insets(
842 0, (dock_bounds_.x() > 0 ? 0 : dock_bounds_.width()),
843 0, (dock_bounds_.x() > 0 ? dock_bounds_.width() : 0));
844 target_bounds->work_area_insets += dock_insets;
847 target_bounds->opacity =
848 (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS ||
849 state.visibility_state == SHELF_VISIBLE ||
850 state.visibility_state == SHELF_AUTO_HIDE) ? 1.0f : 0.0f;
851 target_bounds->status_opacity =
852 (state.visibility_state == SHELF_AUTO_HIDE &&
853 state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN &&
854 gesture_drag_status_ != GESTURE_DRAG_IN_PROGRESS) ?
855 0.0f : target_bounds->opacity;
857 if (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS)
858 UpdateTargetBoundsForGesture(target_bounds);
860 // This needs to happen after calling UpdateTargetBoundsForGesture(), because
861 // that can change the size of the shelf.
862 target_bounds->shelf_bounds_in_shelf = SelectValueForShelfAlignment(
863 gfx::Rect(0, 0,
864 shelf_width - status_size.width(),
865 target_bounds->shelf_bounds_in_root.height()),
866 gfx::Rect(0, 0, target_bounds->shelf_bounds_in_root.width(),
867 shelf_height - status_size.height()),
868 gfx::Rect(0, 0, target_bounds->shelf_bounds_in_root.width(),
869 shelf_height - status_size.height()),
870 gfx::Rect(0, 0,
871 shelf_width - status_size.width(),
872 target_bounds->shelf_bounds_in_root.height()));
875 void ShelfLayoutManager::UpdateTargetBoundsForGesture(
876 TargetBounds* target_bounds) const {
877 CHECK_EQ(GESTURE_DRAG_IN_PROGRESS, gesture_drag_status_);
878 bool horizontal = IsHorizontalAlignment();
879 const gfx::Rect& available_bounds(root_window_->bounds());
880 int resistance_free_region = 0;
882 if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_HIDDEN &&
883 visibility_state() == SHELF_AUTO_HIDE &&
884 auto_hide_state() != SHELF_AUTO_HIDE_SHOWN) {
885 // If the shelf was hidden when the drag started (and the state hasn't
886 // changed since then, e.g. because the tray-menu was shown because of the
887 // drag), then allow the drag some resistance-free region at first to make
888 // sure the shelf sticks with the finger until the shelf is visible.
889 resistance_free_region = kShelfSize - kAutoHideSize;
892 bool resist = SelectValueForShelfAlignment(
893 gesture_drag_amount_ < -resistance_free_region,
894 gesture_drag_amount_ > resistance_free_region,
895 gesture_drag_amount_ < -resistance_free_region,
896 gesture_drag_amount_ > resistance_free_region);
898 float translate = 0.f;
899 if (resist) {
900 float diff = fabsf(gesture_drag_amount_) - resistance_free_region;
901 diff = std::min(diff, sqrtf(diff));
902 if (gesture_drag_amount_ < 0)
903 translate = -resistance_free_region - diff;
904 else
905 translate = resistance_free_region + diff;
906 } else {
907 translate = gesture_drag_amount_;
910 if (horizontal) {
911 // Move and size the shelf with the gesture.
912 int shelf_height = target_bounds->shelf_bounds_in_root.height() - translate;
913 shelf_height = std::max(shelf_height, kAutoHideSize);
914 target_bounds->shelf_bounds_in_root.set_height(shelf_height);
915 if (GetAlignment() == SHELF_ALIGNMENT_BOTTOM) {
916 target_bounds->shelf_bounds_in_root.set_y(
917 available_bounds.bottom() - shelf_height);
920 target_bounds->status_bounds_in_shelf.set_y(0);
921 } else {
922 // Move and size the shelf with the gesture.
923 int shelf_width = target_bounds->shelf_bounds_in_root.width();
924 bool right_aligned = GetAlignment() == SHELF_ALIGNMENT_RIGHT;
925 if (right_aligned)
926 shelf_width -= translate;
927 else
928 shelf_width += translate;
929 shelf_width = std::max(shelf_width, kAutoHideSize);
930 target_bounds->shelf_bounds_in_root.set_width(shelf_width);
931 if (right_aligned) {
932 target_bounds->shelf_bounds_in_root.set_x(
933 available_bounds.right() - shelf_width);
936 if (right_aligned)
937 target_bounds->status_bounds_in_shelf.set_x(0);
938 else
939 target_bounds->status_bounds_in_shelf.set_x(
940 target_bounds->shelf_bounds_in_root.width() -
941 kShelfSize);
945 void ShelfLayoutManager::UpdateShelfBackground(
946 BackgroundAnimatorChangeType type) {
947 const ShelfBackgroundType background_type(GetShelfBackgroundType());
948 shelf_->SetPaintsBackground(background_type, type);
949 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
950 OnBackgroundUpdated(background_type, type));
953 ShelfBackgroundType ShelfLayoutManager::GetShelfBackgroundType() const {
954 if (state_.visibility_state != SHELF_AUTO_HIDE &&
955 state_.window_state == WORKSPACE_WINDOW_STATE_MAXIMIZED) {
956 return SHELF_BACKGROUND_MAXIMIZED;
959 if (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS ||
960 (!state_.is_screen_locked && !state_.is_adding_user_screen &&
961 window_overlaps_shelf_) ||
962 (state_.visibility_state == SHELF_AUTO_HIDE)) {
963 return SHELF_BACKGROUND_OVERLAP;
966 return SHELF_BACKGROUND_DEFAULT;
969 void ShelfLayoutManager::UpdateAutoHideStateNow() {
970 SetState(state_.visibility_state);
972 // If the state did not change, the auto hide timer may still be running.
973 StopAutoHideTimer();
976 void ShelfLayoutManager::StopAutoHideTimer() {
977 auto_hide_timer_.Stop();
978 mouse_over_shelf_when_auto_hide_timer_started_ = false;
981 gfx::Rect ShelfLayoutManager::GetAutoHideShowShelfRegionInScreen() const {
982 gfx::Rect shelf_bounds_in_screen = shelf_->GetWindowBoundsInScreen();
983 gfx::Vector2d offset = SelectValueForShelfAlignment(
984 gfx::Vector2d(0, shelf_bounds_in_screen.height()),
985 gfx::Vector2d(-kMaxAutoHideShowShelfRegionSize, 0),
986 gfx::Vector2d(shelf_bounds_in_screen.width(), 0),
987 gfx::Vector2d(0, -kMaxAutoHideShowShelfRegionSize));
989 gfx::Rect show_shelf_region_in_screen = shelf_bounds_in_screen;
990 show_shelf_region_in_screen += offset;
991 if (IsHorizontalAlignment())
992 show_shelf_region_in_screen.set_height(kMaxAutoHideShowShelfRegionSize);
993 else
994 show_shelf_region_in_screen.set_width(kMaxAutoHideShowShelfRegionSize);
996 // TODO: Figure out if we need any special handling when the keyboard is
997 // visible.
998 return show_shelf_region_in_screen;
1001 ShelfAutoHideState ShelfLayoutManager::CalculateAutoHideState(
1002 ShelfVisibilityState visibility_state) const {
1003 if (visibility_state != SHELF_AUTO_HIDE || !shelf_)
1004 return SHELF_AUTO_HIDE_HIDDEN;
1006 Shell* shell = Shell::GetInstance();
1007 // Unhide the shelf only on the active screen when the AppList is shown
1008 // (crbug.com/312445).
1009 if (shell->GetAppListTargetVisibility()) {
1010 aura::Window* active_window = wm::GetActiveWindow();
1011 aura::Window* shelf_window = shelf_->GetNativeWindow();
1012 if (active_window && shelf_window &&
1013 active_window->GetRootWindow() == shelf_window->GetRootWindow()) {
1014 return SHELF_AUTO_HIDE_SHOWN;
1018 if (shelf_->status_area_widget() &&
1019 shelf_->status_area_widget()->ShouldShowShelf())
1020 return SHELF_AUTO_HIDE_SHOWN;
1022 if (shelf_->shelf() && shelf_->shelf()->IsShowingMenu())
1023 return SHELF_AUTO_HIDE_SHOWN;
1025 if (shelf_->shelf() && shelf_->shelf()->IsShowingOverflowBubble())
1026 return SHELF_AUTO_HIDE_SHOWN;
1028 if (shelf_->IsActive() ||
1029 (shelf_->status_area_widget() &&
1030 shelf_->status_area_widget()->IsActive()))
1031 return SHELF_AUTO_HIDE_SHOWN;
1033 const std::vector<aura::Window*> windows =
1034 ash::MruWindowTracker::BuildWindowList();
1036 // Process the window list and check if there are any visible windows.
1037 bool visible_window = false;
1038 for (size_t i = 0; i < windows.size(); ++i) {
1039 if (windows[i] && windows[i]->IsVisible() &&
1040 !wm::GetWindowState(windows[i])->IsMinimized() &&
1041 root_window_ == windows[i]->GetRootWindow()) {
1042 visible_window = true;
1043 break;
1046 // If there are no visible windows do not hide the shelf.
1047 if (!visible_window)
1048 return SHELF_AUTO_HIDE_SHOWN;
1050 if (gesture_drag_status_ == GESTURE_DRAG_COMPLETE_IN_PROGRESS)
1051 return gesture_drag_auto_hide_state_;
1053 // Don't show if the user is dragging the mouse.
1054 if (auto_hide_event_filter_.get() && auto_hide_event_filter_->in_mouse_drag())
1055 return SHELF_AUTO_HIDE_HIDDEN;
1057 // Ignore the mouse position if mouse events are disabled.
1058 aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(
1059 shelf_->GetNativeWindow()->GetRootWindow());
1060 if (!cursor_client->IsMouseEventsEnabled())
1061 return SHELF_AUTO_HIDE_HIDDEN;
1063 gfx::Rect shelf_region = shelf_->GetWindowBoundsInScreen();
1064 if (shelf_->status_area_widget() &&
1065 shelf_->status_area_widget()->IsMessageBubbleShown() &&
1066 IsVisible()) {
1067 // Increase the the hit test area to prevent the shelf from disappearing
1068 // when the mouse is over the bubble gap.
1069 ShelfAlignment alignment = GetAlignment();
1070 shelf_region.Inset(alignment == SHELF_ALIGNMENT_RIGHT ?
1071 -kNotificationBubbleGapHeight : 0,
1072 alignment == SHELF_ALIGNMENT_BOTTOM ?
1073 -kNotificationBubbleGapHeight : 0,
1074 alignment == SHELF_ALIGNMENT_LEFT ?
1075 -kNotificationBubbleGapHeight : 0,
1076 alignment == SHELF_ALIGNMENT_TOP ?
1077 -kNotificationBubbleGapHeight : 0);
1080 gfx::Point cursor_position_in_screen =
1081 Shell::GetScreen()->GetCursorScreenPoint();
1082 if (shelf_region.Contains(cursor_position_in_screen))
1083 return SHELF_AUTO_HIDE_SHOWN;
1085 // When the shelf is auto hidden and the shelf is on the boundary between two
1086 // displays, it is hard to trigger showing the shelf. For instance, if a
1087 // user's primary display is left of their secondary display, it is hard to
1088 // unautohide a left aligned shelf on the secondary display.
1089 // It is hard because:
1090 // - It is hard to stop the cursor in the shelf "light bar" and not overshoot.
1091 // - The cursor is warped to the other display if the cursor gets to the edge
1092 // of the display.
1093 // Show the shelf if the cursor started on the shelf and the user overshot the
1094 // shelf slightly to make it easier to show the shelf in this situation. We
1095 // do not check |auto_hide_timer_|.IsRunning() because it returns false when
1096 // the timer's task is running.
1097 if ((state_.auto_hide_state == SHELF_AUTO_HIDE_SHOWN ||
1098 mouse_over_shelf_when_auto_hide_timer_started_) &&
1099 GetAutoHideShowShelfRegionInScreen().Contains(
1100 cursor_position_in_screen)) {
1101 return SHELF_AUTO_HIDE_SHOWN;
1104 return SHELF_AUTO_HIDE_HIDDEN;
1107 bool ShelfLayoutManager::IsShelfWindow(aura::Window* window) {
1108 if (!window)
1109 return false;
1110 return (shelf_ && shelf_->GetNativeWindow()->Contains(window)) ||
1111 (shelf_->status_area_widget() &&
1112 shelf_->status_area_widget()->GetNativeWindow()->Contains(window));
1115 int ShelfLayoutManager::GetWorkAreaSize(const State& state, int size) const {
1116 if (state.visibility_state == SHELF_VISIBLE)
1117 return size;
1118 if (state.visibility_state == SHELF_AUTO_HIDE)
1119 return kAutoHideSize;
1120 return 0;
1123 void ShelfLayoutManager::OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) {
1124 bool keyboard_is_about_to_hide = false;
1125 if (new_bounds.IsEmpty() && !keyboard_bounds_.IsEmpty())
1126 keyboard_is_about_to_hide = true;
1128 keyboard_bounds_ = new_bounds;
1129 OnWindowResized();
1131 SessionStateDelegate* session_state_delegate =
1132 Shell::GetInstance()->session_state_delegate();
1134 // On login screen if keyboard has been just hidden, update bounds just once
1135 // but ignore target_bounds.work_area_insets since shelf overlaps with login
1136 // window.
1137 if (session_state_delegate->IsUserSessionBlocked() &&
1138 keyboard_is_about_to_hide) {
1139 Shell::GetInstance()->SetDisplayWorkAreaInsets(root_window_, gfx::Insets());
1143 void ShelfLayoutManager::OnDockBoundsChanging(
1144 const gfx::Rect& dock_bounds,
1145 DockedWindowLayoutManagerObserver::Reason reason) {
1146 // Skip shelf layout in case docked notification originates from this class.
1147 if (reason == DISPLAY_INSETS_CHANGED)
1148 return;
1149 if (dock_bounds_ != dock_bounds) {
1150 dock_bounds_ = dock_bounds;
1151 OnWindowResized();
1152 UpdateVisibilityState();
1153 UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE);
1157 void ShelfLayoutManager::OnLockStateEvent(LockStateObserver::EventType event) {
1158 if (event == EVENT_LOCK_ANIMATION_STARTED) {
1159 // Enter the screen locked state and update the visibility to avoid an odd
1160 // animation when transitioning the orientation from L/R to bottom.
1161 state_.is_screen_locked = true;
1162 UpdateShelfVisibilityAfterLoginUIChange();
1166 void ShelfLayoutManager::SessionStateChanged(
1167 SessionStateDelegate::SessionState state) {
1168 // Check transition changes to/from the add user to session and change the
1169 // shelf alignment accordingly
1170 bool add_user = state == SessionStateDelegate::SESSION_STATE_LOGIN_SECONDARY;
1171 if (add_user != state_.is_adding_user_screen) {
1172 state_.is_adding_user_screen = add_user;
1173 UpdateShelfVisibilityAfterLoginUIChange();
1174 return;
1176 TargetBounds target_bounds;
1177 CalculateTargetBounds(state_, &target_bounds);
1178 UpdateBoundsAndOpacity(target_bounds, true, NULL);
1179 UpdateVisibilityState();
1182 void ShelfLayoutManager::UpdateShelfVisibilityAfterLoginUIChange() {
1183 shelf_->SetAlignment(state_.is_adding_user_screen || state_.is_screen_locked ?
1184 SHELF_ALIGNMENT_BOTTOM : alignment_);
1185 UpdateVisibilityState();
1186 LayoutShelf();
1189 } // namespace ash