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"
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"
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.
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();
83 const int ShelfLayoutManager::kWorkspaceAreaVisibleInset
= 2;
86 const int ShelfLayoutManager::kWorkspaceAreaAutoHideInset
= 5;
89 const int ShelfLayoutManager::kAutoHideSize
= 3;
92 const int ShelfLayoutManager::kShelfItemInset
= 3;
94 // ShelfLayoutManager::AutoHideEventFilter -------------------------------------
96 // Notifies ShelfLayoutManager any time the mouse moves.
97 class ShelfLayoutManager::AutoHideEventFilter
: public ui::EventHandler
{
99 explicit AutoHideEventFilter(ShelfLayoutManager
* shelf
);
100 ~AutoHideEventFilter() override
;
102 // Returns true if the last mouse event was a mouse drag.
103 bool in_mouse_drag() const { return in_mouse_drag_
; }
105 // Overridden from ui::EventHandler:
106 void OnMouseEvent(ui::MouseEvent
* event
) override
;
107 void OnGestureEvent(ui::GestureEvent
* event
) override
;
110 ShelfLayoutManager
* shelf_
;
112 ShelfGestureHandler gesture_handler_
;
113 DISALLOW_COPY_AND_ASSIGN(AutoHideEventFilter
);
116 ShelfLayoutManager::AutoHideEventFilter::AutoHideEventFilter(
117 ShelfLayoutManager
* shelf
)
119 in_mouse_drag_(false) {
120 Shell::GetInstance()->AddPreTargetHandler(this);
123 ShelfLayoutManager::AutoHideEventFilter::~AutoHideEventFilter() {
124 Shell::GetInstance()->RemovePreTargetHandler(this);
127 void ShelfLayoutManager::AutoHideEventFilter::OnMouseEvent(
128 ui::MouseEvent
* event
) {
129 // This also checks IsShelfWindow() to make sure we don't attempt to hide the
130 // shelf if the mouse down occurs on the shelf.
131 in_mouse_drag_
= (event
->type() == ui::ET_MOUSE_DRAGGED
||
132 (in_mouse_drag_
&& event
->type() != ui::ET_MOUSE_RELEASED
&&
133 event
->type() != ui::ET_MOUSE_CAPTURE_CHANGED
)) &&
134 !shelf_
->IsShelfWindow(static_cast<aura::Window
*>(event
->target()));
135 if (event
->type() == ui::ET_MOUSE_MOVED
)
136 shelf_
->UpdateAutoHideState();
140 void ShelfLayoutManager::AutoHideEventFilter::OnGestureEvent(
141 ui::GestureEvent
* event
) {
142 aura::Window
* target_window
= static_cast<aura::Window
*>(event
->target());
143 if (shelf_
->IsShelfWindow(target_window
)) {
144 if (gesture_handler_
.ProcessGestureEvent(*event
, target_window
))
145 event
->StopPropagation();
149 // ShelfLayoutManager:UpdateShelfObserver --------------------------------------
151 // UpdateShelfObserver is used to delay updating the background until the
152 // animation completes.
153 class ShelfLayoutManager::UpdateShelfObserver
154 : public ui::ImplicitAnimationObserver
{
156 explicit UpdateShelfObserver(ShelfLayoutManager
* shelf
) : shelf_(shelf
) {
157 shelf_
->update_shelf_observer_
= this;
164 void OnImplicitAnimationsCompleted() override
{
166 shelf_
->UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE
);
171 ~UpdateShelfObserver() override
{
173 shelf_
->update_shelf_observer_
= NULL
;
176 // Shelf we're in. NULL if deleted before we're deleted.
177 ShelfLayoutManager
* shelf_
;
179 DISALLOW_COPY_AND_ASSIGN(UpdateShelfObserver
);
182 // ShelfLayoutManager ----------------------------------------------------------
184 ShelfLayoutManager::ShelfLayoutManager(ShelfWidget
* shelf
)
185 : SnapToPixelLayoutManager(shelf
->GetNativeView()->parent()),
186 root_window_(shelf
->GetNativeView()->GetRootWindow()),
187 updating_bounds_(false),
188 auto_hide_behavior_(SHELF_AUTO_HIDE_BEHAVIOR_NEVER
),
189 alignment_(SHELF_ALIGNMENT_BOTTOM
),
191 workspace_controller_(NULL
),
192 window_overlaps_shelf_(false),
193 mouse_over_shelf_when_auto_hide_timer_started_(false),
194 bezel_event_filter_(new ShelfBezelEventFilter(this)),
195 gesture_drag_status_(GESTURE_DRAG_NONE
),
196 gesture_drag_amount_(0.f
),
197 gesture_drag_auto_hide_state_(SHELF_AUTO_HIDE_SHOWN
),
198 update_shelf_observer_(NULL
),
199 duration_override_in_ms_(0) {
200 Shell::GetInstance()->AddShellObserver(this);
201 Shell::GetInstance()->lock_state_controller()->AddObserver(this);
202 aura::client::GetActivationClient(root_window_
)->AddObserver(this);
203 Shell::GetInstance()->session_state_delegate()->AddSessionStateObserver(this);
206 ShelfLayoutManager::~ShelfLayoutManager() {
207 if (update_shelf_observer_
)
208 update_shelf_observer_
->Detach();
210 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver
, observers_
, WillDeleteShelf());
211 Shell::GetInstance()->RemoveShellObserver(this);
212 Shell::GetInstance()->lock_state_controller()->RemoveObserver(this);
213 Shell::GetInstance()->
214 session_state_delegate()->RemoveSessionStateObserver(this);
217 void ShelfLayoutManager::SetAutoHideBehavior(ShelfAutoHideBehavior behavior
) {
218 if (auto_hide_behavior_
== behavior
)
220 auto_hide_behavior_
= behavior
;
221 UpdateVisibilityState();
222 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver
, observers_
,
223 OnAutoHideBehaviorChanged(root_window_
,
224 auto_hide_behavior_
));
227 void ShelfLayoutManager::PrepareForShutdown() {
228 // Clear all event filters, otherwise sometimes those filters may catch
229 // synthesized mouse event and cause crashes during the shutdown.
230 set_workspace_controller(NULL
);
231 auto_hide_event_filter_
.reset();
232 bezel_event_filter_
.reset();
233 // Stop observing window change, otherwise we can attempt to update a
234 // partially destructed shelf.
235 aura::client::GetActivationClient(root_window_
)->RemoveObserver(this);
238 bool ShelfLayoutManager::IsVisible() const {
239 // status_area_widget() may be NULL during the shutdown.
240 return shelf_
->status_area_widget() &&
241 shelf_
->status_area_widget()->IsVisible() &&
242 (state_
.visibility_state
== SHELF_VISIBLE
||
243 (state_
.visibility_state
== SHELF_AUTO_HIDE
&&
244 state_
.auto_hide_state
== SHELF_AUTO_HIDE_SHOWN
));
247 bool ShelfLayoutManager::SetAlignment(ShelfAlignment alignment
) {
248 if (alignment_
== alignment
)
251 alignment_
= alignment
;
252 // The shelf will itself move to the bottom while locked or obscured by user
253 // login. If a request is sent to move while being obscured, we postpone the
254 // move until the user session is resumed.
255 if (IsAlignmentLocked())
258 // This should not be called during the lock screen transitions.
259 shelf_
->SetAlignment(alignment
);
264 ShelfAlignment
ShelfLayoutManager::GetAlignment() const {
265 // When the screen is locked or a user gets added, the shelf is forced into
267 if (IsAlignmentLocked())
268 return SHELF_ALIGNMENT_BOTTOM
;
272 gfx::Rect
ShelfLayoutManager::GetIdealBounds() {
274 ScreenUtil::GetDisplayBoundsInParent(shelf_
->GetNativeView()));
275 int width
= 0, height
= 0;
276 GetShelfSize(&width
, &height
);
277 return SelectValueForShelfAlignment(
278 gfx::Rect(bounds
.x(), bounds
.bottom() - height
, bounds
.width(), height
),
279 gfx::Rect(bounds
.x(), bounds
.y(), width
, bounds
.height()),
280 gfx::Rect(bounds
.right() - width
, bounds
.y(), width
, bounds
.height()),
281 gfx::Rect(bounds
.x(), bounds
.y(), bounds
.width(), height
));
284 void ShelfLayoutManager::LayoutShelf() {
285 TargetBounds target_bounds
;
286 CalculateTargetBounds(state_
, &target_bounds
);
287 UpdateBoundsAndOpacity(target_bounds
, false, NULL
);
289 if (shelf_
->shelf()) {
290 // This is not part of UpdateBoundsAndOpacity() because
291 // SetShelfViewBounds() sets the bounds immediately and does not animate.
292 // The height of the ShelfView for a horizontal shelf and the width of
293 // the ShelfView for a vertical shelf are set when |shelf_|'s bounds
294 // are changed via UpdateBoundsAndOpacity(). This sets the origin and the
295 // dimension in the other direction.
296 shelf_
->shelf()->SetShelfViewBounds(
297 target_bounds
.shelf_bounds_in_shelf
);
298 // Update insets in ShelfWindowTargeter when shelf bounds change.
299 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver
, observers_
,
300 WillChangeVisibilityState(visibility_state()));
304 ShelfVisibilityState
ShelfLayoutManager::CalculateShelfVisibility() {
305 switch(auto_hide_behavior_
) {
306 case SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS
:
308 // Disable shelf auto-hide behavior on screen sides in Metro mode.
309 if (GetAlignment() != SHELF_ALIGNMENT_BOTTOM
)
310 return SHELF_VISIBLE
;
312 return SHELF_AUTO_HIDE
;
313 case SHELF_AUTO_HIDE_BEHAVIOR_NEVER
:
314 return SHELF_VISIBLE
;
315 case SHELF_AUTO_HIDE_ALWAYS_HIDDEN
:
318 return SHELF_VISIBLE
;
321 void ShelfLayoutManager::UpdateVisibilityState() {
322 // Bail out early when there is no |workspace_controller_|, which happens
323 // during shutdown after PrepareForShutdown.
324 if (!workspace_controller_
)
327 if (state_
.is_screen_locked
|| state_
.is_adding_user_screen
) {
328 SetState(SHELF_VISIBLE
);
330 // TODO(zelidrag): Verify shelf drag animation still shows on the device
331 // when we are in SHELF_AUTO_HIDE_ALWAYS_HIDDEN.
332 WorkspaceWindowState
window_state(workspace_controller_
->GetWindowState());
333 switch (window_state
) {
334 case WORKSPACE_WINDOW_STATE_FULL_SCREEN
: {
335 const aura::Window
* fullscreen_window
= GetRootWindowController(
336 root_window_
)->GetWindowForFullscreenMode();
337 if (fullscreen_window
&& wm::GetWindowState(fullscreen_window
)->
338 hide_shelf_when_fullscreen()) {
339 SetState(SHELF_HIDDEN
);
341 // The shelf is sometimes not hidden when in immersive fullscreen.
342 // Force the shelf to be auto hidden in this case.
343 SetState(SHELF_AUTO_HIDE
);
348 case WORKSPACE_WINDOW_STATE_MAXIMIZED
:
349 SetState(CalculateShelfVisibility());
352 case WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF
:
353 case WORKSPACE_WINDOW_STATE_DEFAULT
:
354 SetState(CalculateShelfVisibility());
355 SetWindowOverlapsShelf(window_state
==
356 WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF
);
362 void ShelfLayoutManager::UpdateAutoHideState() {
363 ShelfAutoHideState auto_hide_state
=
364 CalculateAutoHideState(state_
.visibility_state
);
365 if (auto_hide_state
!= state_
.auto_hide_state
) {
366 if (auto_hide_state
== SHELF_AUTO_HIDE_HIDDEN
) {
367 // Hides happen immediately.
368 SetState(state_
.visibility_state
);
370 if (!auto_hide_timer_
.IsRunning()) {
371 mouse_over_shelf_when_auto_hide_timer_started_
=
372 shelf_
->GetWindowBoundsInScreen().Contains(
373 Shell::GetScreen()->GetCursorScreenPoint());
375 auto_hide_timer_
.Start(
377 base::TimeDelta::FromMilliseconds(kAutoHideDelayMS
),
378 this, &ShelfLayoutManager::UpdateAutoHideStateNow
);
385 void ShelfLayoutManager::SetWindowOverlapsShelf(bool value
) {
386 window_overlaps_shelf_
= value
;
387 UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE
);
390 void ShelfLayoutManager::AddObserver(ShelfLayoutManagerObserver
* observer
) {
391 observers_
.AddObserver(observer
);
394 void ShelfLayoutManager::RemoveObserver(ShelfLayoutManagerObserver
* observer
) {
395 observers_
.RemoveObserver(observer
);
398 ////////////////////////////////////////////////////////////////////////////////
399 // ShelfLayoutManager, Gesture functions:
401 void ShelfLayoutManager::OnGestureEdgeSwipe(const ui::GestureEvent
& gesture
) {
402 if (visibility_state() == SHELF_AUTO_HIDE
) {
403 gesture_drag_auto_hide_state_
= SHELF_AUTO_HIDE_SHOWN
;
404 gesture_drag_status_
= GESTURE_DRAG_COMPLETE_IN_PROGRESS
;
405 UpdateVisibilityState();
406 gesture_drag_status_
= GESTURE_DRAG_NONE
;
410 void ShelfLayoutManager::StartGestureDrag(const ui::GestureEvent
& gesture
) {
411 gesture_drag_status_
= GESTURE_DRAG_IN_PROGRESS
;
412 gesture_drag_amount_
= 0.f
;
413 gesture_drag_auto_hide_state_
= visibility_state() == SHELF_AUTO_HIDE
?
414 auto_hide_state() : SHELF_AUTO_HIDE_SHOWN
;
415 UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE
);
418 void ShelfLayoutManager::UpdateGestureDrag(
419 const ui::GestureEvent
& gesture
) {
420 bool horizontal
= IsHorizontalAlignment();
421 gesture_drag_amount_
+= horizontal
? gesture
.details().scroll_y() :
422 gesture
.details().scroll_x();
426 void ShelfLayoutManager::CompleteGestureDrag(const ui::GestureEvent
& gesture
) {
427 bool horizontal
= IsHorizontalAlignment();
428 bool should_change
= false;
429 if (gesture
.type() == ui::ET_GESTURE_SCROLL_END
) {
430 // The visibility of the shelf changes only if the shelf was dragged X%
431 // along the correct axis. If the shelf was already visible, then the
432 // direction of the drag does not matter.
433 const float kDragHideThreshold
= 0.4f
;
434 gfx::Rect bounds
= GetIdealBounds();
435 float drag_ratio
= fabs(gesture_drag_amount_
) /
436 (horizontal
? bounds
.height() : bounds
.width());
437 if (gesture_drag_auto_hide_state_
== SHELF_AUTO_HIDE_SHOWN
) {
438 should_change
= drag_ratio
> kDragHideThreshold
;
440 bool correct_direction
= false;
441 switch (GetAlignment()) {
442 case SHELF_ALIGNMENT_BOTTOM
:
443 case SHELF_ALIGNMENT_RIGHT
:
444 correct_direction
= gesture_drag_amount_
< 0;
446 case SHELF_ALIGNMENT_LEFT
:
447 case SHELF_ALIGNMENT_TOP
:
448 correct_direction
= gesture_drag_amount_
> 0;
451 should_change
= correct_direction
&& drag_ratio
> kDragHideThreshold
;
453 } else if (gesture
.type() == ui::ET_SCROLL_FLING_START
) {
454 if (gesture_drag_auto_hide_state_
== SHELF_AUTO_HIDE_SHOWN
) {
455 should_change
= horizontal
? fabs(gesture
.details().velocity_y()) > 0 :
456 fabs(gesture
.details().velocity_x()) > 0;
458 should_change
= SelectValueForShelfAlignment(
459 gesture
.details().velocity_y() < 0,
460 gesture
.details().velocity_x() > 0,
461 gesture
.details().velocity_x() < 0,
462 gesture
.details().velocity_y() > 0);
468 if (!should_change
) {
473 shelf_
->Deactivate();
474 shelf_
->status_area_widget()->Deactivate();
476 gesture_drag_auto_hide_state_
=
477 gesture_drag_auto_hide_state_
== SHELF_AUTO_HIDE_SHOWN
?
478 SHELF_AUTO_HIDE_HIDDEN
: SHELF_AUTO_HIDE_SHOWN
;
479 ShelfAutoHideBehavior new_auto_hide_behavior
=
480 gesture_drag_auto_hide_state_
== SHELF_AUTO_HIDE_SHOWN
?
481 SHELF_AUTO_HIDE_BEHAVIOR_NEVER
: SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS
;
483 // When in fullscreen and the shelf is forced to be auto hidden, the auto hide
484 // behavior affects neither the visibility state nor the auto hide state. Set
485 // |gesture_drag_status_| to GESTURE_DRAG_COMPLETE_IN_PROGRESS to set the auto
486 // hide state to |gesture_drag_auto_hide_state_|.
487 gesture_drag_status_
= GESTURE_DRAG_COMPLETE_IN_PROGRESS
;
488 if (auto_hide_behavior_
!= new_auto_hide_behavior
)
489 SetAutoHideBehavior(new_auto_hide_behavior
);
491 UpdateVisibilityState();
492 gesture_drag_status_
= GESTURE_DRAG_NONE
;
495 void ShelfLayoutManager::CancelGestureDrag() {
496 gesture_drag_status_
= GESTURE_DRAG_CANCEL_IN_PROGRESS
;
497 UpdateVisibilityState();
498 gesture_drag_status_
= GESTURE_DRAG_NONE
;
501 void ShelfLayoutManager::SetAnimationDurationOverride(
502 int duration_override_in_ms
) {
503 duration_override_in_ms_
= duration_override_in_ms
;
506 ////////////////////////////////////////////////////////////////////////////////
507 // ShelfLayoutManager, aura::LayoutManager implementation:
509 void ShelfLayoutManager::OnWindowResized() {
513 void ShelfLayoutManager::SetChildBounds(aura::Window
* child
,
514 const gfx::Rect
& requested_bounds
) {
515 SnapToPixelLayoutManager::SetChildBounds(child
, requested_bounds
);
516 // We may contain other widgets (such as frame maximize bubble) but they don't
517 // effect the layout in anyway.
518 if (!updating_bounds_
&&
519 ((shelf_
->GetNativeView() == child
) ||
520 (shelf_
->status_area_widget()->GetNativeView() == child
))) {
525 void ShelfLayoutManager::OnLockStateChanged(bool locked
) {
526 // Force the shelf to layout for alignment (bottom if locked, restore
527 // the previous alignment otherwise).
528 state_
.is_screen_locked
= locked
;
529 UpdateShelfVisibilityAfterLoginUIChange();
532 void ShelfLayoutManager::OnWindowActivated(
533 aura::client::ActivationChangeObserver::ActivationReason reason
,
534 aura::Window
* gained_active
,
535 aura::Window
* lost_active
) {
536 UpdateAutoHideStateNow();
539 bool ShelfLayoutManager::IsHorizontalAlignment() const {
540 return GetAlignment() == SHELF_ALIGNMENT_BOTTOM
||
541 GetAlignment() == SHELF_ALIGNMENT_TOP
;
545 ShelfLayoutManager
* ShelfLayoutManager::ForShelf(aura::Window
* window
) {
546 ShelfWidget
* shelf
= RootWindowController::ForShelf(window
)->shelf();
547 return shelf
? shelf
->shelf_layout_manager() : NULL
;
550 ////////////////////////////////////////////////////////////////////////////////
551 // ShelfLayoutManager, private:
553 ShelfLayoutManager::TargetBounds::TargetBounds()
554 : opacity(0.0f
), status_opacity(0.0f
) {}
556 ShelfLayoutManager::TargetBounds::~TargetBounds() {}
558 void ShelfLayoutManager::SetState(ShelfVisibilityState visibility_state
) {
559 if (!shelf_
->GetNativeView())
563 state
.visibility_state
= visibility_state
;
564 state
.auto_hide_state
= CalculateAutoHideState(visibility_state
);
565 state
.window_state
= workspace_controller_
?
566 workspace_controller_
->GetWindowState() : WORKSPACE_WINDOW_STATE_DEFAULT
;
567 // Preserve the log in screen states.
568 state
.is_adding_user_screen
= state_
.is_adding_user_screen
;
569 state
.is_screen_locked
= state_
.is_screen_locked
;
571 // Force an update because gesture drags affect the shelf bounds and we
572 // should animate back to the normal bounds at the end of a gesture.
574 (gesture_drag_status_
== GESTURE_DRAG_CANCEL_IN_PROGRESS
||
575 gesture_drag_status_
== GESTURE_DRAG_COMPLETE_IN_PROGRESS
);
577 if (!force_update
&& state_
.Equals(state
))
578 return; // Nothing changed.
580 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver
, observers_
,
581 WillChangeVisibilityState(visibility_state
));
583 if (state
.visibility_state
== SHELF_AUTO_HIDE
) {
584 // When state is SHELF_AUTO_HIDE we need to track when the mouse is over the
585 // shelf to unhide it. AutoHideEventFilter does that for us.
586 if (!auto_hide_event_filter_
)
587 auto_hide_event_filter_
.reset(new AutoHideEventFilter(this));
589 auto_hide_event_filter_
.reset(NULL
);
594 State old_state
= state_
;
597 BackgroundAnimatorChangeType change_type
= BACKGROUND_CHANGE_ANIMATE
;
598 bool delay_background_change
= false;
600 // Do not animate the background when:
601 // - Going from a hidden / auto hidden shelf in fullscreen to a visible shelf
602 // in maximized mode.
603 // - Going from an auto hidden shelf in maximized mode to a visible shelf in
605 if (state
.visibility_state
== SHELF_VISIBLE
&&
606 state
.window_state
== WORKSPACE_WINDOW_STATE_MAXIMIZED
&&
607 old_state
.visibility_state
!= SHELF_VISIBLE
) {
608 change_type
= BACKGROUND_CHANGE_IMMEDIATE
;
610 // Delay the animation when the shelf was hidden, and has just been made
611 // visible (e.g. using a gesture-drag).
612 if (state
.visibility_state
== SHELF_VISIBLE
&&
613 old_state
.visibility_state
== SHELF_AUTO_HIDE
&&
614 old_state
.auto_hide_state
== SHELF_AUTO_HIDE_HIDDEN
) {
615 delay_background_change
= true;
619 if (delay_background_change
) {
620 if (update_shelf_observer_
)
621 update_shelf_observer_
->Detach();
622 // UpdateShelfBackground deletes itself when the animation is done.
623 update_shelf_observer_
= new UpdateShelfObserver(this);
625 UpdateShelfBackground(change_type
);
628 shelf_
->SetDimsShelf(
629 state
.visibility_state
== SHELF_VISIBLE
&&
630 state
.window_state
== WORKSPACE_WINDOW_STATE_MAXIMIZED
);
632 TargetBounds target_bounds
;
633 CalculateTargetBounds(state_
, &target_bounds
);
634 UpdateBoundsAndOpacity(target_bounds
, true,
635 delay_background_change
? update_shelf_observer_
: NULL
);
637 // OnAutoHideStateChanged Should be emitted when:
638 // - firstly state changed to auto-hide from other state
639 // - or, auto_hide_state has changed
640 if ((old_state
.visibility_state
!= state_
.visibility_state
&&
641 state_
.visibility_state
== SHELF_AUTO_HIDE
) ||
642 old_state
.auto_hide_state
!= state_
.auto_hide_state
) {
643 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver
, observers_
,
644 OnAutoHideStateChanged(state_
.auto_hide_state
));
648 void ShelfLayoutManager::UpdateBoundsAndOpacity(
649 const TargetBounds
& target_bounds
,
651 ui::ImplicitAnimationObserver
* observer
) {
652 base::AutoReset
<bool> auto_reset_updating_bounds(&updating_bounds_
, true);
654 ui::ScopedLayerAnimationSettings
shelf_animation_setter(
655 GetLayer(shelf_
)->GetAnimator());
656 ui::ScopedLayerAnimationSettings
status_animation_setter(
657 GetLayer(shelf_
->status_area_widget())->GetAnimator());
659 int duration
= duration_override_in_ms_
? duration_override_in_ms_
:
660 kCrossFadeDurationMS
;
661 shelf_animation_setter
.SetTransitionDuration(
662 base::TimeDelta::FromMilliseconds(duration
));
663 shelf_animation_setter
.SetTweenType(gfx::Tween::EASE_OUT
);
664 shelf_animation_setter
.SetPreemptionStrategy(
665 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
666 status_animation_setter
.SetTransitionDuration(
667 base::TimeDelta::FromMilliseconds(duration
));
668 status_animation_setter
.SetTweenType(gfx::Tween::EASE_OUT
);
669 status_animation_setter
.SetPreemptionStrategy(
670 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
673 shelf_animation_setter
.SetTransitionDuration(base::TimeDelta());
674 status_animation_setter
.SetTransitionDuration(base::TimeDelta());
677 status_animation_setter
.AddObserver(observer
);
679 GetLayer(shelf_
)->SetOpacity(target_bounds
.opacity
);
680 shelf_
->SetBounds(ScreenUtil::ConvertRectToScreen(
681 shelf_
->GetNativeView()->parent(),
682 target_bounds
.shelf_bounds_in_root
));
684 GetLayer(shelf_
->status_area_widget())->SetOpacity(
685 target_bounds
.status_opacity
);
687 // Having a window which is visible but does not have an opacity is an
688 // illegal state. We therefore hide the shelf here if required.
689 if (!target_bounds
.status_opacity
)
690 shelf_
->status_area_widget()->Hide();
691 // Setting visibility during an animation causes the visibility property to
692 // animate. Override the animation settings to immediately set the
693 // visibility property. Opacity will still animate.
695 // TODO(harrym): Once status area widget is a child view of shelf
696 // this can be simplified.
697 gfx::Rect status_bounds
= target_bounds
.status_bounds_in_shelf
;
698 status_bounds
.set_x(status_bounds
.x() +
699 target_bounds
.shelf_bounds_in_root
.x());
700 status_bounds
.set_y(status_bounds
.y() +
701 target_bounds
.shelf_bounds_in_root
.y());
702 shelf_
->status_area_widget()->SetBounds(
703 ScreenUtil::ConvertRectToScreen(
704 shelf_
->status_area_widget()->GetNativeView()->parent(),
706 if (!state_
.is_screen_locked
) {
708 // If user session is blocked (login to new user session or add user to
709 // the existing session - multi-profile) then give 100% of work area only
710 // if keyboard is not shown.
711 if (!state_
.is_adding_user_screen
|| !keyboard_bounds_
.IsEmpty()) {
712 insets
= target_bounds
.work_area_insets
;
714 Shell::GetInstance()->SetDisplayWorkAreaInsets(root_window_
, insets
);
718 // Setting visibility during an animation causes the visibility property to
719 // animate. Set the visibility property without an animation.
720 if (target_bounds
.status_opacity
)
721 shelf_
->status_area_widget()->Show();
724 void ShelfLayoutManager::StopAnimating() {
725 GetLayer(shelf_
)->GetAnimator()->StopAnimating();
726 GetLayer(shelf_
->status_area_widget())->GetAnimator()->StopAnimating();
729 void ShelfLayoutManager::GetShelfSize(int* width
, int* height
) {
730 *width
= *height
= 0;
731 gfx::Size
status_size(
732 shelf_
->status_area_widget()->GetWindowBoundsInScreen().size());
733 if (IsHorizontalAlignment())
734 *height
= kShelfSize
;
739 void ShelfLayoutManager::AdjustBoundsBasedOnAlignment(int inset
,
740 gfx::Rect
* bounds
) const {
741 bounds
->Inset(SelectValueForShelfAlignment(
742 gfx::Insets(0, 0, inset
, 0),
743 gfx::Insets(0, inset
, 0, 0),
744 gfx::Insets(0, 0, 0, inset
),
745 gfx::Insets(inset
, 0, 0, 0)));
748 void ShelfLayoutManager::CalculateTargetBounds(
750 TargetBounds
* target_bounds
) {
751 gfx::Rect available_bounds
=
752 ScreenUtil::GetShelfDisplayBoundsInScreen(root_window_
);
754 ScreenUtil::ConvertRectFromScreen(root_window_
, available_bounds
);
756 gfx::Rect
status_size(
757 shelf_
->status_area_widget()->GetWindowBoundsInScreen().size());
758 int shelf_width
= 0, shelf_height
= 0;
759 GetShelfSize(&shelf_width
, &shelf_height
);
760 if (IsHorizontalAlignment())
761 shelf_width
= available_bounds
.width();
763 shelf_height
= available_bounds
.height();
765 if (state
.visibility_state
== SHELF_AUTO_HIDE
&&
766 state
.auto_hide_state
== SHELF_AUTO_HIDE_HIDDEN
) {
767 // Auto-hidden shelf always starts with the default size. If a gesture-drag
768 // is in progress, then the call to UpdateTargetBoundsForGesture() below
769 // takes care of setting the height properly.
770 if (IsHorizontalAlignment())
771 shelf_height
= kAutoHideSize
;
773 shelf_width
= kAutoHideSize
;
774 } else if (state
.visibility_state
== SHELF_HIDDEN
||
775 (!keyboard_bounds_
.IsEmpty() && !keyboard::IsKeyboardOverscrollEnabled()))
777 if (IsHorizontalAlignment())
783 int bottom_shelf_vertical_offset
= available_bounds
.bottom();
784 if (keyboard_bounds_
.IsEmpty())
785 bottom_shelf_vertical_offset
-= shelf_height
;
787 bottom_shelf_vertical_offset
-= keyboard_bounds_
.height();
789 target_bounds
->shelf_bounds_in_root
= SelectValueForShelfAlignment(
790 gfx::Rect(available_bounds
.x(), bottom_shelf_vertical_offset
,
791 available_bounds
.width(), shelf_height
),
792 gfx::Rect(available_bounds
.x(), available_bounds
.y(),
793 shelf_width
, available_bounds
.height()),
794 gfx::Rect(available_bounds
.right() - shelf_width
, available_bounds
.y(),
795 shelf_width
, available_bounds
.height()),
796 gfx::Rect(available_bounds
.x(), available_bounds
.y(),
797 available_bounds
.width(), shelf_height
));
799 if (IsHorizontalAlignment())
800 status_size
.set_height(kShelfSize
);
802 status_size
.set_width(kShelfSize
);
804 target_bounds
->status_bounds_in_shelf
= SelectValueForShelfAlignment(
805 gfx::Rect(base::i18n::IsRTL() ? 0 : shelf_width
- status_size
.width(),
806 0, status_size
.width(), status_size
.height()),
807 gfx::Rect(shelf_width
- status_size
.width(),
808 shelf_height
- status_size
.height(), status_size
.width(),
809 status_size
.height()),
810 gfx::Rect(0, shelf_height
- status_size
.height(),
811 status_size
.width(), status_size
.height()),
812 gfx::Rect(base::i18n::IsRTL() ? 0 : shelf_width
- status_size
.width(),
813 shelf_height
- status_size
.height(),
814 status_size
.width(), status_size
.height()));
816 target_bounds
->work_area_insets
= SelectValueForShelfAlignment(
817 gfx::Insets(0, 0, GetWorkAreaSize(state
, shelf_height
), 0),
818 gfx::Insets(0, GetWorkAreaSize(state
, shelf_width
), 0, 0),
819 gfx::Insets(0, 0, 0, GetWorkAreaSize(state
, shelf_width
)),
820 gfx::Insets(GetWorkAreaSize(state
, shelf_height
), 0, 0, 0));
822 // TODO(varkha): The functionality of managing insets for display areas
823 // should probably be pushed to a separate component. This would simplify or
824 // remove entirely the dependency on keyboard and dock.
826 if (!keyboard_bounds_
.IsEmpty() && !keyboard::IsKeyboardOverscrollEnabled()) {
827 // Also push in the work area inset for the keyboard if it is visible.
828 gfx::Insets
keyboard_insets(0, 0, keyboard_bounds_
.height(), 0);
829 target_bounds
->work_area_insets
+= keyboard_insets
;
832 // Also push in the work area inset for the dock if it is visible.
833 if (!dock_bounds_
.IsEmpty()) {
834 gfx::Insets
dock_insets(
835 0, (dock_bounds_
.x() > 0 ? 0 : dock_bounds_
.width()),
836 0, (dock_bounds_
.x() > 0 ? dock_bounds_
.width() : 0));
837 target_bounds
->work_area_insets
+= dock_insets
;
840 target_bounds
->opacity
=
841 (gesture_drag_status_
== GESTURE_DRAG_IN_PROGRESS
||
842 state
.visibility_state
== SHELF_VISIBLE
||
843 state
.visibility_state
== SHELF_AUTO_HIDE
) ? 1.0f
: 0.0f
;
844 target_bounds
->status_opacity
=
845 (state
.visibility_state
== SHELF_AUTO_HIDE
&&
846 state
.auto_hide_state
== SHELF_AUTO_HIDE_HIDDEN
&&
847 gesture_drag_status_
!= GESTURE_DRAG_IN_PROGRESS
) ?
848 0.0f
: target_bounds
->opacity
;
850 if (gesture_drag_status_
== GESTURE_DRAG_IN_PROGRESS
)
851 UpdateTargetBoundsForGesture(target_bounds
);
853 // This needs to happen after calling UpdateTargetBoundsForGesture(), because
854 // that can change the size of the shelf.
855 target_bounds
->shelf_bounds_in_shelf
= SelectValueForShelfAlignment(
857 shelf_width
- status_size
.width(),
858 target_bounds
->shelf_bounds_in_root
.height()),
859 gfx::Rect(0, 0, target_bounds
->shelf_bounds_in_root
.width(),
860 shelf_height
- status_size
.height()),
861 gfx::Rect(0, 0, target_bounds
->shelf_bounds_in_root
.width(),
862 shelf_height
- status_size
.height()),
864 shelf_width
- status_size
.width(),
865 target_bounds
->shelf_bounds_in_root
.height()));
867 available_bounds
.Subtract(target_bounds
->shelf_bounds_in_root
);
868 available_bounds
.Subtract(keyboard_bounds_
);
869 user_work_area_bounds_
=
870 ScreenUtil::ConvertRectToScreen(root_window_
, available_bounds
);
873 void ShelfLayoutManager::UpdateTargetBoundsForGesture(
874 TargetBounds
* target_bounds
) const {
875 CHECK_EQ(GESTURE_DRAG_IN_PROGRESS
, gesture_drag_status_
);
876 bool horizontal
= IsHorizontalAlignment();
877 const gfx::Rect
& available_bounds(root_window_
->bounds());
878 int resistance_free_region
= 0;
880 if (gesture_drag_auto_hide_state_
== SHELF_AUTO_HIDE_HIDDEN
&&
881 visibility_state() == SHELF_AUTO_HIDE
&&
882 auto_hide_state() != SHELF_AUTO_HIDE_SHOWN
) {
883 // If the shelf was hidden when the drag started (and the state hasn't
884 // changed since then, e.g. because the tray-menu was shown because of the
885 // drag), then allow the drag some resistance-free region at first to make
886 // sure the shelf sticks with the finger until the shelf is visible.
887 resistance_free_region
= kShelfSize
- kAutoHideSize
;
890 bool resist
= SelectValueForShelfAlignment(
891 gesture_drag_amount_
< -resistance_free_region
,
892 gesture_drag_amount_
> resistance_free_region
,
893 gesture_drag_amount_
< -resistance_free_region
,
894 gesture_drag_amount_
> resistance_free_region
);
896 float translate
= 0.f
;
898 float diff
= fabsf(gesture_drag_amount_
) - resistance_free_region
;
899 diff
= std::min(diff
, sqrtf(diff
));
900 if (gesture_drag_amount_
< 0)
901 translate
= -resistance_free_region
- diff
;
903 translate
= resistance_free_region
+ diff
;
905 translate
= gesture_drag_amount_
;
909 // Move and size the shelf with the gesture.
910 int shelf_height
= target_bounds
->shelf_bounds_in_root
.height() - translate
;
911 shelf_height
= std::max(shelf_height
, kAutoHideSize
);
912 target_bounds
->shelf_bounds_in_root
.set_height(shelf_height
);
913 if (GetAlignment() == SHELF_ALIGNMENT_BOTTOM
) {
914 target_bounds
->shelf_bounds_in_root
.set_y(
915 available_bounds
.bottom() - shelf_height
);
918 target_bounds
->status_bounds_in_shelf
.set_y(0);
920 // Move and size the shelf with the gesture.
921 int shelf_width
= target_bounds
->shelf_bounds_in_root
.width();
922 bool right_aligned
= GetAlignment() == SHELF_ALIGNMENT_RIGHT
;
924 shelf_width
-= translate
;
926 shelf_width
+= translate
;
927 shelf_width
= std::max(shelf_width
, kAutoHideSize
);
928 target_bounds
->shelf_bounds_in_root
.set_width(shelf_width
);
930 target_bounds
->shelf_bounds_in_root
.set_x(
931 available_bounds
.right() - shelf_width
);
935 target_bounds
->status_bounds_in_shelf
.set_x(0);
937 target_bounds
->status_bounds_in_shelf
.set_x(
938 target_bounds
->shelf_bounds_in_root
.width() -
943 void ShelfLayoutManager::UpdateShelfBackground(
944 BackgroundAnimatorChangeType type
) {
945 const ShelfBackgroundType
background_type(GetShelfBackgroundType());
946 shelf_
->SetPaintsBackground(background_type
, type
);
947 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver
, observers_
,
948 OnBackgroundUpdated(background_type
, type
));
951 ShelfBackgroundType
ShelfLayoutManager::GetShelfBackgroundType() const {
952 if (state_
.visibility_state
!= SHELF_AUTO_HIDE
&&
953 state_
.window_state
== WORKSPACE_WINDOW_STATE_MAXIMIZED
) {
954 return SHELF_BACKGROUND_MAXIMIZED
;
957 if (gesture_drag_status_
== GESTURE_DRAG_IN_PROGRESS
||
958 (!state_
.is_screen_locked
&& !state_
.is_adding_user_screen
&&
959 window_overlaps_shelf_
) ||
960 (state_
.visibility_state
== SHELF_AUTO_HIDE
)) {
961 return SHELF_BACKGROUND_OVERLAP
;
964 return SHELF_BACKGROUND_DEFAULT
;
967 void ShelfLayoutManager::UpdateAutoHideStateNow() {
968 SetState(state_
.visibility_state
);
970 // If the state did not change, the auto hide timer may still be running.
974 void ShelfLayoutManager::StopAutoHideTimer() {
975 auto_hide_timer_
.Stop();
976 mouse_over_shelf_when_auto_hide_timer_started_
= false;
979 gfx::Rect
ShelfLayoutManager::GetAutoHideShowShelfRegionInScreen() const {
980 gfx::Rect shelf_bounds_in_screen
= shelf_
->GetWindowBoundsInScreen();
981 gfx::Vector2d offset
= SelectValueForShelfAlignment(
982 gfx::Vector2d(0, shelf_bounds_in_screen
.height()),
983 gfx::Vector2d(-kMaxAutoHideShowShelfRegionSize
, 0),
984 gfx::Vector2d(shelf_bounds_in_screen
.width(), 0),
985 gfx::Vector2d(0, -kMaxAutoHideShowShelfRegionSize
));
987 gfx::Rect show_shelf_region_in_screen
= shelf_bounds_in_screen
;
988 show_shelf_region_in_screen
+= offset
;
989 if (IsHorizontalAlignment())
990 show_shelf_region_in_screen
.set_height(kMaxAutoHideShowShelfRegionSize
);
992 show_shelf_region_in_screen
.set_width(kMaxAutoHideShowShelfRegionSize
);
994 // TODO: Figure out if we need any special handling when the keyboard is
996 return show_shelf_region_in_screen
;
999 ShelfAutoHideState
ShelfLayoutManager::CalculateAutoHideState(
1000 ShelfVisibilityState visibility_state
) const {
1001 if (visibility_state
!= SHELF_AUTO_HIDE
|| !shelf_
)
1002 return SHELF_AUTO_HIDE_HIDDEN
;
1004 Shell
* shell
= Shell::GetInstance();
1005 // Unhide the shelf only on the active screen when the AppList is shown
1006 // (crbug.com/312445).
1007 if (shell
->GetAppListTargetVisibility()) {
1008 aura::Window
* active_window
= wm::GetActiveWindow();
1009 aura::Window
* shelf_window
= shelf_
->GetNativeWindow();
1010 if (active_window
&& shelf_window
&&
1011 active_window
->GetRootWindow() == shelf_window
->GetRootWindow()) {
1012 return SHELF_AUTO_HIDE_SHOWN
;
1016 if (shelf_
->status_area_widget() &&
1017 shelf_
->status_area_widget()->ShouldShowShelf())
1018 return SHELF_AUTO_HIDE_SHOWN
;
1020 if (shelf_
->shelf() && shelf_
->shelf()->IsShowingMenu())
1021 return SHELF_AUTO_HIDE_SHOWN
;
1023 if (shelf_
->shelf() && shelf_
->shelf()->IsShowingOverflowBubble())
1024 return SHELF_AUTO_HIDE_SHOWN
;
1026 if (shelf_
->IsActive() ||
1027 (shelf_
->status_area_widget() &&
1028 shelf_
->status_area_widget()->IsActive()))
1029 return SHELF_AUTO_HIDE_SHOWN
;
1031 const std::vector
<aura::Window
*> windows
=
1032 shell
->mru_window_tracker()->BuildWindowListIgnoreModal();
1034 // Process the window list and check if there are any visible windows.
1035 bool visible_window
= false;
1036 for (size_t i
= 0; i
< windows
.size(); ++i
) {
1037 if (windows
[i
] && windows
[i
]->IsVisible() &&
1038 !wm::GetWindowState(windows
[i
])->IsMinimized() &&
1039 root_window_
== windows
[i
]->GetRootWindow()) {
1040 visible_window
= true;
1044 // If there are no visible windows do not hide the shelf.
1045 if (!visible_window
)
1046 return SHELF_AUTO_HIDE_SHOWN
;
1048 if (gesture_drag_status_
== GESTURE_DRAG_COMPLETE_IN_PROGRESS
)
1049 return gesture_drag_auto_hide_state_
;
1051 // Don't show if the user is dragging the mouse.
1052 if (auto_hide_event_filter_
.get() && auto_hide_event_filter_
->in_mouse_drag())
1053 return SHELF_AUTO_HIDE_HIDDEN
;
1055 // Ignore the mouse position if mouse events are disabled.
1056 aura::client::CursorClient
* cursor_client
= aura::client::GetCursorClient(
1057 shelf_
->GetNativeWindow()->GetRootWindow());
1058 if (!cursor_client
->IsMouseEventsEnabled())
1059 return SHELF_AUTO_HIDE_HIDDEN
;
1061 gfx::Rect shelf_region
= shelf_
->GetWindowBoundsInScreen();
1062 if (shelf_
->status_area_widget() &&
1063 shelf_
->status_area_widget()->IsMessageBubbleShown() &&
1065 // Increase the the hit test area to prevent the shelf from disappearing
1066 // when the mouse is over the bubble gap.
1067 ShelfAlignment alignment
= GetAlignment();
1068 shelf_region
.Inset(alignment
== SHELF_ALIGNMENT_RIGHT
?
1069 -kNotificationBubbleGapHeight
: 0,
1070 alignment
== SHELF_ALIGNMENT_BOTTOM
?
1071 -kNotificationBubbleGapHeight
: 0,
1072 alignment
== SHELF_ALIGNMENT_LEFT
?
1073 -kNotificationBubbleGapHeight
: 0,
1074 alignment
== SHELF_ALIGNMENT_TOP
?
1075 -kNotificationBubbleGapHeight
: 0);
1078 gfx::Point cursor_position_in_screen
=
1079 Shell::GetScreen()->GetCursorScreenPoint();
1080 if (shelf_region
.Contains(cursor_position_in_screen
))
1081 return SHELF_AUTO_HIDE_SHOWN
;
1083 // When the shelf is auto hidden and the shelf is on the boundary between two
1084 // displays, it is hard to trigger showing the shelf. For instance, if a
1085 // user's primary display is left of their secondary display, it is hard to
1086 // unautohide a left aligned shelf on the secondary display.
1087 // It is hard because:
1088 // - It is hard to stop the cursor in the shelf "light bar" and not overshoot.
1089 // - The cursor is warped to the other display if the cursor gets to the edge
1091 // Show the shelf if the cursor started on the shelf and the user overshot the
1092 // shelf slightly to make it easier to show the shelf in this situation. We
1093 // do not check |auto_hide_timer_|.IsRunning() because it returns false when
1094 // the timer's task is running.
1095 if ((state_
.auto_hide_state
== SHELF_AUTO_HIDE_SHOWN
||
1096 mouse_over_shelf_when_auto_hide_timer_started_
) &&
1097 GetAutoHideShowShelfRegionInScreen().Contains(
1098 cursor_position_in_screen
)) {
1099 return SHELF_AUTO_HIDE_SHOWN
;
1102 return SHELF_AUTO_HIDE_HIDDEN
;
1105 bool ShelfLayoutManager::IsShelfWindow(aura::Window
* window
) {
1108 return (shelf_
&& shelf_
->GetNativeWindow()->Contains(window
)) ||
1109 (shelf_
->status_area_widget() &&
1110 shelf_
->status_area_widget()->GetNativeWindow()->Contains(window
));
1113 int ShelfLayoutManager::GetWorkAreaSize(const State
& state
, int size
) const {
1114 if (state
.visibility_state
== SHELF_VISIBLE
)
1116 if (state
.visibility_state
== SHELF_AUTO_HIDE
)
1117 return kAutoHideSize
;
1121 void ShelfLayoutManager::OnKeyboardBoundsChanging(const gfx::Rect
& new_bounds
) {
1122 bool keyboard_is_about_to_hide
= false;
1123 if (new_bounds
.IsEmpty() && !keyboard_bounds_
.IsEmpty())
1124 keyboard_is_about_to_hide
= true;
1126 keyboard_bounds_
= new_bounds
;
1129 SessionStateDelegate
* session_state_delegate
=
1130 Shell::GetInstance()->session_state_delegate();
1132 // On login screen if keyboard has been just hidden, update bounds just once
1133 // but ignore target_bounds.work_area_insets since shelf overlaps with login
1135 if (session_state_delegate
->IsUserSessionBlocked() &&
1136 keyboard_is_about_to_hide
) {
1137 Shell::GetInstance()->SetDisplayWorkAreaInsets(root_window_
, gfx::Insets());
1141 void ShelfLayoutManager::OnDockBoundsChanging(
1142 const gfx::Rect
& dock_bounds
,
1143 DockedWindowLayoutManagerObserver::Reason reason
) {
1144 // Skip shelf layout in case docked notification originates from this class.
1145 if (reason
== DISPLAY_INSETS_CHANGED
)
1147 if (dock_bounds_
!= dock_bounds
) {
1148 dock_bounds_
= dock_bounds
;
1150 UpdateVisibilityState();
1151 UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE
);
1155 void ShelfLayoutManager::OnLockStateEvent(LockStateObserver::EventType event
) {
1156 if (event
== EVENT_LOCK_ANIMATION_STARTED
) {
1157 // Enter the screen locked state and update the visibility to avoid an odd
1158 // animation when transitioning the orientation from L/R to bottom.
1159 state_
.is_screen_locked
= true;
1160 UpdateShelfVisibilityAfterLoginUIChange();
1164 void ShelfLayoutManager::SessionStateChanged(
1165 SessionStateDelegate::SessionState state
) {
1166 // Check transition changes to/from the add user to session and change the
1167 // shelf alignment accordingly
1168 bool add_user
= state
== SessionStateDelegate::SESSION_STATE_LOGIN_SECONDARY
;
1169 if (add_user
!= state_
.is_adding_user_screen
) {
1170 state_
.is_adding_user_screen
= add_user
;
1171 UpdateShelfVisibilityAfterLoginUIChange();
1174 TargetBounds target_bounds
;
1175 CalculateTargetBounds(state_
, &target_bounds
);
1176 UpdateBoundsAndOpacity(target_bounds
, true, NULL
);
1177 UpdateVisibilityState();
1180 void ShelfLayoutManager::UpdateShelfVisibilityAfterLoginUIChange() {
1181 shelf_
->SetAlignment(GetAlignment());
1182 UpdateVisibilityState();
1186 bool ShelfLayoutManager::IsAlignmentLocked() const {
1187 if (state_
.is_screen_locked
)
1189 // The session state becomes active at the start of transitioning to a user
1190 // session, however the session is considered blocked until the full UI is
1191 // ready. Exit early to allow for proper layout.
1192 SessionStateDelegate
* session_state_delegate
=
1193 Shell::GetInstance()->session_state_delegate();
1194 if (session_state_delegate
->GetSessionState() ==
1195 SessionStateDelegate::SESSION_STATE_ACTIVE
) {
1198 if (session_state_delegate
->IsUserSessionBlocked() ||
1199 state_
.is_adding_user_screen
) {