Home | History | Annotate | Download | only in shelf
      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.
      4 
      5 #include "ash/shelf/shelf_layout_manager.h"
      6 
      7 #include <algorithm>
      8 #include <cmath>
      9 #include <cstring>
     10 #include <string>
     11 #include <vector>
     12 
     13 #include "ash/ash_switches.h"
     14 #include "ash/launcher/launcher.h"
     15 #include "ash/launcher/launcher_types.h"
     16 #include "ash/root_window_controller.h"
     17 #include "ash/screen_ash.h"
     18 #include "ash/session_state_delegate.h"
     19 #include "ash/shelf/shelf_bezel_event_filter.h"
     20 #include "ash/shelf/shelf_layout_manager_observer.h"
     21 #include "ash/shelf/shelf_widget.h"
     22 #include "ash/shell.h"
     23 #include "ash/shell_window_ids.h"
     24 #include "ash/system/status_area_widget.h"
     25 #include "ash/wm/gestures/shelf_gesture_handler.h"
     26 #include "ash/wm/lock_state_controller.h"
     27 #include "ash/wm/mru_window_tracker.h"
     28 #include "ash/wm/window_animations.h"
     29 #include "ash/wm/window_state.h"
     30 #include "ash/wm/window_util.h"
     31 #include "ash/wm/workspace_controller.h"
     32 #include "base/auto_reset.h"
     33 #include "base/command_line.h"
     34 #include "base/command_line.h"
     35 #include "base/i18n/rtl.h"
     36 #include "base/strings/string_number_conversions.h"
     37 #include "base/strings/string_util.h"
     38 #include "ui/aura/client/activation_client.h"
     39 #include "ui/aura/client/cursor_client.h"
     40 #include "ui/aura/root_window.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/views/widget/widget.h"
     50 
     51 namespace ash {
     52 namespace internal {
     53 
     54 namespace {
     55 
     56 // Delay before showing the launcher. This is after the mouse stops moving.
     57 const int kAutoHideDelayMS = 200;
     58 
     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;
     63 
     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;
     75 
     76 ui::Layer* GetLayer(views::Widget* widget) {
     77   return widget->GetNativeView()->layer();
     78 }
     79 
     80 bool IsDraggingTrayEnabled() {
     81   static bool dragging_tray_allowed = CommandLine::ForCurrentProcess()->
     82       HasSwitch(ash::switches::kAshEnableTrayDragging);
     83   return dragging_tray_allowed;
     84 }
     85 
     86 }  // namespace
     87 
     88 // static
     89 const int ShelfLayoutManager::kWorkspaceAreaVisibleInset = 2;
     90 
     91 // static
     92 const int ShelfLayoutManager::kWorkspaceAreaAutoHideInset = 5;
     93 
     94 // static
     95 const int ShelfLayoutManager::kAutoHideSize = 3;
     96 
     97 // static
     98 const int ShelfLayoutManager::kShelfSize = 47;
     99 
    100 // static
    101 const int ShelfLayoutManager::kShelfItemInset = 3;
    102 
    103 int ShelfLayoutManager::GetPreferredShelfSize() {
    104   return ash::switches::UseAlternateShelfLayout() ?
    105       ShelfLayoutManager::kShelfSize : kLauncherPreferredSize;
    106 }
    107 
    108 // ShelfLayoutManager::AutoHideEventFilter -------------------------------------
    109 
    110 // Notifies ShelfLayoutManager any time the mouse moves.
    111 class ShelfLayoutManager::AutoHideEventFilter : public ui::EventHandler {
    112  public:
    113   explicit AutoHideEventFilter(ShelfLayoutManager* shelf);
    114   virtual ~AutoHideEventFilter();
    115 
    116   // Returns true if the last mouse event was a mouse drag.
    117   bool in_mouse_drag() const { return in_mouse_drag_; }
    118 
    119   // Overridden from ui::EventHandler:
    120   virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
    121   virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
    122 
    123  private:
    124   ShelfLayoutManager* shelf_;
    125   bool in_mouse_drag_;
    126   ShelfGestureHandler gesture_handler_;
    127   DISALLOW_COPY_AND_ASSIGN(AutoHideEventFilter);
    128 };
    129 
    130 ShelfLayoutManager::AutoHideEventFilter::AutoHideEventFilter(
    131     ShelfLayoutManager* shelf)
    132     : shelf_(shelf),
    133       in_mouse_drag_(false) {
    134   Shell::GetInstance()->AddPreTargetHandler(this);
    135 }
    136 
    137 ShelfLayoutManager::AutoHideEventFilter::~AutoHideEventFilter() {
    138   Shell::GetInstance()->RemovePreTargetHandler(this);
    139 }
    140 
    141 void ShelfLayoutManager::AutoHideEventFilter::OnMouseEvent(
    142     ui::MouseEvent* event) {
    143   // This also checks IsShelfWindow() to make sure we don't attempt to hide the
    144   // shelf if the mouse down occurs on the shelf.
    145   in_mouse_drag_ = (event->type() == ui::ET_MOUSE_DRAGGED ||
    146                     (in_mouse_drag_ && event->type() != ui::ET_MOUSE_RELEASED &&
    147                      event->type() != ui::ET_MOUSE_CAPTURE_CHANGED)) &&
    148       !shelf_->IsShelfWindow(static_cast<aura::Window*>(event->target()));
    149   if (event->type() == ui::ET_MOUSE_MOVED)
    150     shelf_->UpdateAutoHideState();
    151   return;
    152 }
    153 
    154 void ShelfLayoutManager::AutoHideEventFilter::OnGestureEvent(
    155     ui::GestureEvent* event) {
    156   if (shelf_->IsShelfWindow(static_cast<aura::Window*>(event->target()))) {
    157     if (gesture_handler_.ProcessGestureEvent(*event))
    158       event->StopPropagation();
    159   }
    160 }
    161 
    162 // ShelfLayoutManager:UpdateShelfObserver --------------------------------------
    163 
    164 // UpdateShelfObserver is used to delay updating the background until the
    165 // animation completes.
    166 class ShelfLayoutManager::UpdateShelfObserver
    167     : public ui::ImplicitAnimationObserver {
    168  public:
    169   explicit UpdateShelfObserver(ShelfLayoutManager* shelf) : shelf_(shelf) {
    170     shelf_->update_shelf_observer_ = this;
    171   }
    172 
    173   void Detach() {
    174     shelf_ = NULL;
    175   }
    176 
    177   virtual void OnImplicitAnimationsCompleted() OVERRIDE {
    178     if (shelf_)
    179       shelf_->UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE);
    180     delete this;
    181   }
    182 
    183  private:
    184   virtual ~UpdateShelfObserver() {
    185     if (shelf_)
    186       shelf_->update_shelf_observer_ = NULL;
    187   }
    188 
    189   // Shelf we're in. NULL if deleted before we're deleted.
    190   ShelfLayoutManager* shelf_;
    191 
    192   DISALLOW_COPY_AND_ASSIGN(UpdateShelfObserver);
    193 };
    194 
    195 // ShelfLayoutManager ----------------------------------------------------------
    196 
    197 ShelfLayoutManager::ShelfLayoutManager(ShelfWidget* shelf)
    198     : root_window_(shelf->GetNativeView()->GetRootWindow()),
    199       updating_bounds_(false),
    200       auto_hide_behavior_(SHELF_AUTO_HIDE_BEHAVIOR_NEVER),
    201       alignment_(SHELF_ALIGNMENT_BOTTOM),
    202       shelf_(shelf),
    203       workspace_controller_(NULL),
    204       window_overlaps_shelf_(false),
    205       mouse_over_shelf_when_auto_hide_timer_started_(false),
    206       bezel_event_filter_(new ShelfBezelEventFilter(this)),
    207       gesture_drag_status_(GESTURE_DRAG_NONE),
    208       gesture_drag_amount_(0.f),
    209       gesture_drag_auto_hide_state_(SHELF_AUTO_HIDE_SHOWN),
    210       update_shelf_observer_(NULL) {
    211   Shell::GetInstance()->AddShellObserver(this);
    212   Shell::GetInstance()->lock_state_controller()->AddObserver(this);
    213   aura::client::GetActivationClient(root_window_)->AddObserver(this);
    214 }
    215 
    216 ShelfLayoutManager::~ShelfLayoutManager() {
    217   if (update_shelf_observer_)
    218     update_shelf_observer_->Detach();
    219 
    220   FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_, WillDeleteShelf());
    221   Shell::GetInstance()->RemoveShellObserver(this);
    222   Shell::GetInstance()->lock_state_controller()->RemoveObserver(this);
    223   aura::client::GetActivationClient(root_window_)->RemoveObserver(this);
    224 }
    225 
    226 void ShelfLayoutManager::SetAutoHideBehavior(ShelfAutoHideBehavior behavior) {
    227   if (auto_hide_behavior_ == behavior)
    228     return;
    229   auto_hide_behavior_ = behavior;
    230   UpdateVisibilityState();
    231   FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
    232                     OnAutoHideBehaviorChanged(root_window_,
    233                                               auto_hide_behavior_));
    234 }
    235 
    236 void ShelfLayoutManager::PrepareForShutdown() {
    237   // Clear all event filters, otherwise sometimes those filters may catch
    238   // synthesized mouse event and cause crashes during the shutdown.
    239   set_workspace_controller(NULL);
    240   auto_hide_event_filter_.reset();
    241   bezel_event_filter_.reset();
    242 }
    243 
    244 bool ShelfLayoutManager::IsVisible() const {
    245   // status_area_widget() may be NULL during the shutdown.
    246   return shelf_->status_area_widget() &&
    247       shelf_->status_area_widget()->IsVisible() &&
    248       (state_.visibility_state == SHELF_VISIBLE ||
    249        (state_.visibility_state == SHELF_AUTO_HIDE &&
    250         state_.auto_hide_state == SHELF_AUTO_HIDE_SHOWN));
    251 }
    252 
    253 bool ShelfLayoutManager::SetAlignment(ShelfAlignment alignment) {
    254   if (alignment_ == alignment)
    255     return false;
    256 
    257   // This should not be called during the lock screen transitions.
    258   DCHECK(!Shell::GetInstance()->session_state_delegate()->IsScreenLocked());
    259   alignment_ = alignment;
    260   shelf_->SetAlignment(alignment);
    261   LayoutShelf();
    262   return true;
    263 }
    264 
    265 ShelfAlignment ShelfLayoutManager::GetAlignment() const {
    266   // When the screen is locked, the shelf is forced into bottom alignment.
    267   if (Shell::GetInstance()->session_state_delegate()->IsScreenLocked())
    268     return SHELF_ALIGNMENT_BOTTOM;
    269   return alignment_;
    270 }
    271 
    272 gfx::Rect ShelfLayoutManager::GetIdealBounds() {
    273   gfx::Rect bounds(
    274       ScreenAsh::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));
    282 }
    283 
    284 void ShelfLayoutManager::LayoutShelf() {
    285   TargetBounds target_bounds;
    286   CalculateTargetBounds(state_, &target_bounds);
    287   UpdateBoundsAndOpacity(target_bounds, false, NULL);
    288 
    289   if (shelf_->launcher()) {
    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_->launcher()->SetShelfViewBounds(
    297         target_bounds.launcher_bounds_in_shelf);
    298   }
    299 }
    300 
    301 ShelfVisibilityState ShelfLayoutManager::CalculateShelfVisibility() {
    302   switch(auto_hide_behavior_) {
    303     case SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS:
    304       return SHELF_AUTO_HIDE;
    305     case SHELF_AUTO_HIDE_BEHAVIOR_NEVER:
    306       return SHELF_VISIBLE;
    307     case SHELF_AUTO_HIDE_ALWAYS_HIDDEN:
    308       return SHELF_HIDDEN;
    309   }
    310   return SHELF_VISIBLE;
    311 }
    312 
    313 void ShelfLayoutManager::UpdateVisibilityState() {
    314   // Bail out early when there is no |workspace_controller_|, which happens
    315   // during shutdown after PrepareForShutdown.
    316   if (!workspace_controller_)
    317     return;
    318 
    319   if (Shell::GetInstance()->session_state_delegate()->IsScreenLocked()) {
    320     SetState(SHELF_VISIBLE);
    321   } else {
    322     // TODO(zelidrag): Verify shelf drag animation still shows on the device
    323     // when we are in SHELF_AUTO_HIDE_ALWAYS_HIDDEN.
    324     WorkspaceWindowState window_state(workspace_controller_->GetWindowState());
    325     switch (window_state) {
    326       case WORKSPACE_WINDOW_STATE_FULL_SCREEN: {
    327         const aura::Window* fullscreen_window = GetRootWindowController(
    328             root_window_)->GetWindowForFullscreenMode();
    329         if (fullscreen_window && wm::GetWindowState(fullscreen_window)->
    330                 hide_shelf_when_fullscreen()) {
    331           SetState(SHELF_HIDDEN);
    332         } else {
    333           // The shelf is sometimes not hidden when in immersive fullscreen.
    334           // Force the shelf to be auto hidden in this case.
    335           SetState(SHELF_AUTO_HIDE);
    336         }
    337         break;
    338       }
    339 
    340       case WORKSPACE_WINDOW_STATE_MAXIMIZED:
    341         SetState(CalculateShelfVisibility());
    342         break;
    343 
    344       case WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF:
    345       case WORKSPACE_WINDOW_STATE_DEFAULT:
    346         SetState(CalculateShelfVisibility());
    347         SetWindowOverlapsShelf(window_state ==
    348                                WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF);
    349         break;
    350     }
    351   }
    352 }
    353 
    354 void ShelfLayoutManager::UpdateAutoHideState() {
    355   ShelfAutoHideState auto_hide_state =
    356       CalculateAutoHideState(state_.visibility_state);
    357   if (auto_hide_state != state_.auto_hide_state) {
    358     if (auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) {
    359       // Hides happen immediately.
    360       SetState(state_.visibility_state);
    361     } else {
    362       if (!auto_hide_timer_.IsRunning()) {
    363         mouse_over_shelf_when_auto_hide_timer_started_ =
    364             shelf_->GetWindowBoundsInScreen().Contains(
    365                 Shell::GetScreen()->GetCursorScreenPoint());
    366       }
    367       auto_hide_timer_.Start(
    368           FROM_HERE,
    369           base::TimeDelta::FromMilliseconds(kAutoHideDelayMS),
    370           this, &ShelfLayoutManager::UpdateAutoHideStateNow);
    371     }
    372   } else {
    373     StopAutoHideTimer();
    374   }
    375 }
    376 
    377 void ShelfLayoutManager::SetWindowOverlapsShelf(bool value) {
    378   window_overlaps_shelf_ = value;
    379   UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE);
    380 }
    381 
    382 void ShelfLayoutManager::AddObserver(ShelfLayoutManagerObserver* observer) {
    383   observers_.AddObserver(observer);
    384 }
    385 
    386 void ShelfLayoutManager::RemoveObserver(ShelfLayoutManagerObserver* observer) {
    387   observers_.RemoveObserver(observer);
    388 }
    389 
    390 ////////////////////////////////////////////////////////////////////////////////
    391 // ShelfLayoutManager, Gesture dragging:
    392 
    393 void ShelfLayoutManager::StartGestureDrag(const ui::GestureEvent& gesture) {
    394   gesture_drag_status_ = GESTURE_DRAG_IN_PROGRESS;
    395   gesture_drag_amount_ = 0.f;
    396   gesture_drag_auto_hide_state_ = visibility_state() == SHELF_AUTO_HIDE ?
    397       auto_hide_state() : SHELF_AUTO_HIDE_SHOWN;
    398   UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE);
    399 }
    400 
    401 ShelfLayoutManager::DragState ShelfLayoutManager::UpdateGestureDrag(
    402     const ui::GestureEvent& gesture) {
    403   bool horizontal = IsHorizontalAlignment();
    404   gesture_drag_amount_ += horizontal ? gesture.details().scroll_y() :
    405                                        gesture.details().scroll_x();
    406   LayoutShelf();
    407 
    408   // Start reveling the status menu when:
    409   //   - dragging up on an already visible shelf
    410   //   - dragging up on a hidden shelf, but it is currently completely visible.
    411   if (horizontal && gesture.details().scroll_y() < 0) {
    412     int min_height = 0;
    413     if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_HIDDEN && shelf_)
    414       min_height = shelf_->GetContentsView()->GetPreferredSize().height();
    415 
    416     if (min_height < shelf_->GetWindowBoundsInScreen().height() &&
    417         gesture.root_location().x() >=
    418         shelf_->status_area_widget()->GetWindowBoundsInScreen().x() &&
    419         IsDraggingTrayEnabled())
    420       return DRAG_TRAY;
    421   }
    422 
    423   return DRAG_SHELF;
    424 }
    425 
    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;
    439     } else {
    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;
    445           break;
    446         case SHELF_ALIGNMENT_LEFT:
    447         case SHELF_ALIGNMENT_TOP:
    448           correct_direction = gesture_drag_amount_ > 0;
    449           break;
    450       }
    451       should_change = correct_direction && drag_ratio > kDragHideThreshold;
    452     }
    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;
    457     } else {
    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);
    463     }
    464   } else {
    465     NOTREACHED();
    466   }
    467 
    468   if (!should_change) {
    469     CancelGestureDrag();
    470     return;
    471   }
    472   if (shelf_) {
    473     shelf_->Deactivate();
    474     shelf_->status_area_widget()->Deactivate();
    475   }
    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;
    482 
    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);
    490   else
    491     UpdateVisibilityState();
    492   gesture_drag_status_ = GESTURE_DRAG_NONE;
    493 }
    494 
    495 void ShelfLayoutManager::CancelGestureDrag() {
    496   gesture_drag_status_ = GESTURE_DRAG_CANCEL_IN_PROGRESS;
    497   UpdateVisibilityState();
    498   gesture_drag_status_ = GESTURE_DRAG_NONE;
    499 }
    500 
    501 ////////////////////////////////////////////////////////////////////////////////
    502 // ShelfLayoutManager, aura::LayoutManager implementation:
    503 
    504 void ShelfLayoutManager::OnWindowResized() {
    505   LayoutShelf();
    506 }
    507 
    508 void ShelfLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
    509 }
    510 
    511 void ShelfLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) {
    512 }
    513 
    514 void ShelfLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
    515 }
    516 
    517 void ShelfLayoutManager::OnChildWindowVisibilityChanged(aura::Window* child,
    518                                                         bool visible) {
    519 }
    520 
    521 void ShelfLayoutManager::SetChildBounds(aura::Window* child,
    522                                         const gfx::Rect& requested_bounds) {
    523   SetChildBoundsDirect(child, requested_bounds);
    524   // We may contain other widgets (such as frame maximize bubble) but they don't
    525   // effect the layout in anyway.
    526   if (!updating_bounds_ &&
    527       ((shelf_->GetNativeView() == child) ||
    528        (shelf_->status_area_widget()->GetNativeView() == child))) {
    529     LayoutShelf();
    530   }
    531 }
    532 
    533 void ShelfLayoutManager::OnLockStateChanged(bool locked) {
    534   // Force the shelf to layout for alignment (bottom if locked, restore
    535   // the previous alignment otherwise).
    536   shelf_->SetAlignment(locked ? SHELF_ALIGNMENT_BOTTOM : alignment_);
    537   UpdateVisibilityState();
    538   LayoutShelf();
    539 }
    540 
    541 void ShelfLayoutManager::OnWindowActivated(aura::Window* gained_active,
    542                                            aura::Window* lost_active) {
    543   UpdateAutoHideStateNow();
    544 }
    545 
    546 bool ShelfLayoutManager::IsHorizontalAlignment() const {
    547   return GetAlignment() == SHELF_ALIGNMENT_BOTTOM ||
    548          GetAlignment() == SHELF_ALIGNMENT_TOP;
    549 }
    550 
    551 // static
    552 ShelfLayoutManager* ShelfLayoutManager::ForLauncher(aura::Window* window) {
    553   ShelfWidget* shelf = RootWindowController::ForLauncher(window)->shelf();
    554   return shelf ? shelf->shelf_layout_manager() : NULL;
    555 }
    556 
    557 ////////////////////////////////////////////////////////////////////////////////
    558 // ShelfLayoutManager, private:
    559 
    560 ShelfLayoutManager::TargetBounds::TargetBounds() : opacity(0.0f) {}
    561 ShelfLayoutManager::TargetBounds::~TargetBounds() {}
    562 
    563 void ShelfLayoutManager::SetState(ShelfVisibilityState visibility_state) {
    564   if (!shelf_->GetNativeView())
    565     return;
    566 
    567   State state;
    568   state.visibility_state = visibility_state;
    569   state.auto_hide_state = CalculateAutoHideState(visibility_state);
    570   state.is_screen_locked =
    571       Shell::GetInstance()->session_state_delegate()->IsScreenLocked();
    572   state.window_state = workspace_controller_ ?
    573       workspace_controller_->GetWindowState() : WORKSPACE_WINDOW_STATE_DEFAULT;
    574 
    575   // Force an update because gesture drags affect the shelf bounds and we
    576   // should animate back to the normal bounds at the end of a gesture.
    577   bool force_update =
    578       (gesture_drag_status_ == GESTURE_DRAG_CANCEL_IN_PROGRESS ||
    579        gesture_drag_status_ == GESTURE_DRAG_COMPLETE_IN_PROGRESS);
    580 
    581   if (!force_update && state_.Equals(state))
    582     return;  // Nothing changed.
    583 
    584   FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
    585                     WillChangeVisibilityState(visibility_state));
    586 
    587   if (state.visibility_state == SHELF_AUTO_HIDE) {
    588     // When state is SHELF_AUTO_HIDE we need to track when the mouse is over the
    589     // launcher to unhide the shelf. AutoHideEventFilter does that for us.
    590     if (!auto_hide_event_filter_)
    591       auto_hide_event_filter_.reset(new AutoHideEventFilter(this));
    592   } else {
    593     auto_hide_event_filter_.reset(NULL);
    594   }
    595 
    596   StopAutoHideTimer();
    597 
    598   State old_state = state_;
    599   state_ = state;
    600 
    601   BackgroundAnimatorChangeType change_type = BACKGROUND_CHANGE_ANIMATE;
    602   bool delay_background_change = false;
    603 
    604   // Do not animate the background when:
    605   // - Going from a hidden / auto hidden shelf in fullscreen to a visible shelf
    606   //   in maximized mode.
    607   // - Going from an auto hidden shelf in maximized mode to a visible shelf in
    608   //   maximized mode.
    609   if (state.visibility_state == SHELF_VISIBLE &&
    610       state.window_state == WORKSPACE_WINDOW_STATE_MAXIMIZED &&
    611       old_state.visibility_state != SHELF_VISIBLE) {
    612     change_type = BACKGROUND_CHANGE_IMMEDIATE;
    613   } else {
    614     // Delay the animation when the shelf was hidden, and has just been made
    615     // visible (e.g. using a gesture-drag).
    616     if (state.visibility_state == SHELF_VISIBLE &&
    617         old_state.visibility_state == SHELF_AUTO_HIDE &&
    618         old_state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) {
    619       delay_background_change = true;
    620     }
    621   }
    622 
    623   if (delay_background_change) {
    624     if (update_shelf_observer_)
    625       update_shelf_observer_->Detach();
    626     // UpdateShelfBackground deletes itself when the animation is done.
    627     update_shelf_observer_ = new UpdateShelfObserver(this);
    628   } else {
    629     UpdateShelfBackground(change_type);
    630   }
    631 
    632   shelf_->SetDimsShelf(
    633       state.visibility_state == SHELF_VISIBLE &&
    634       state.window_state == WORKSPACE_WINDOW_STATE_MAXIMIZED);
    635 
    636   TargetBounds target_bounds;
    637   CalculateTargetBounds(state_, &target_bounds);
    638   UpdateBoundsAndOpacity(target_bounds, true,
    639       delay_background_change ? update_shelf_observer_ : NULL);
    640 
    641   // OnAutoHideStateChanged Should be emitted when:
    642   //  - firstly state changed to auto-hide from other state
    643   //  - or, auto_hide_state has changed
    644   if ((old_state.visibility_state != state_.visibility_state &&
    645        state_.visibility_state == SHELF_AUTO_HIDE) ||
    646       old_state.auto_hide_state != state_.auto_hide_state) {
    647     FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
    648                       OnAutoHideStateChanged(state_.auto_hide_state));
    649   }
    650 }
    651 
    652 void ShelfLayoutManager::UpdateBoundsAndOpacity(
    653     const TargetBounds& target_bounds,
    654     bool animate,
    655     ui::ImplicitAnimationObserver* observer) {
    656   base::AutoReset<bool> auto_reset_updating_bounds(&updating_bounds_, true);
    657 
    658   ui::ScopedLayerAnimationSettings launcher_animation_setter(
    659       GetLayer(shelf_)->GetAnimator());
    660   ui::ScopedLayerAnimationSettings status_animation_setter(
    661       GetLayer(shelf_->status_area_widget())->GetAnimator());
    662   if (animate) {
    663     launcher_animation_setter.SetTransitionDuration(
    664         base::TimeDelta::FromMilliseconds(kCrossFadeDurationMS));
    665     launcher_animation_setter.SetTweenType(gfx::Tween::EASE_OUT);
    666     launcher_animation_setter.SetPreemptionStrategy(
    667         ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
    668     status_animation_setter.SetTransitionDuration(
    669         base::TimeDelta::FromMilliseconds(kCrossFadeDurationMS));
    670     status_animation_setter.SetTweenType(gfx::Tween::EASE_OUT);
    671     status_animation_setter.SetPreemptionStrategy(
    672         ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
    673   } else {
    674     StopAnimating();
    675     launcher_animation_setter.SetTransitionDuration(base::TimeDelta());
    676     status_animation_setter.SetTransitionDuration(base::TimeDelta());
    677   }
    678   if (observer)
    679     status_animation_setter.AddObserver(observer);
    680 
    681   GetLayer(shelf_)->SetOpacity(target_bounds.opacity);
    682   shelf_->SetBounds(ScreenAsh::ConvertRectToScreen(
    683        shelf_->GetNativeView()->parent(),
    684        target_bounds.shelf_bounds_in_root));
    685 
    686   GetLayer(shelf_->status_area_widget())->SetOpacity(
    687       target_bounds.status_opacity);
    688   // TODO(harrym): Once status area widget is a child view of shelf
    689   // this can be simplified.
    690   gfx::Rect status_bounds = target_bounds.status_bounds_in_shelf;
    691   status_bounds.set_x(status_bounds.x() +
    692                       target_bounds.shelf_bounds_in_root.x());
    693   status_bounds.set_y(status_bounds.y() +
    694                       target_bounds.shelf_bounds_in_root.y());
    695   shelf_->status_area_widget()->SetBounds(
    696       ScreenAsh::ConvertRectToScreen(
    697           shelf_->status_area_widget()->GetNativeView()->parent(),
    698           status_bounds));
    699   Shell::GetInstance()->SetDisplayWorkAreaInsets(
    700       root_window_, target_bounds.work_area_insets);
    701   UpdateHitTestBounds();
    702 }
    703 
    704 void ShelfLayoutManager::StopAnimating() {
    705   GetLayer(shelf_)->GetAnimator()->StopAnimating();
    706   GetLayer(shelf_->status_area_widget())->GetAnimator()->StopAnimating();
    707 }
    708 
    709 void ShelfLayoutManager::GetShelfSize(int* width, int* height) {
    710   *width = *height = 0;
    711   gfx::Size status_size(
    712       shelf_->status_area_widget()->GetWindowBoundsInScreen().size());
    713   if (IsHorizontalAlignment())
    714     *height = GetPreferredShelfSize();
    715   else
    716     *width = GetPreferredShelfSize();
    717 }
    718 
    719 void ShelfLayoutManager::AdjustBoundsBasedOnAlignment(int inset,
    720                                                       gfx::Rect* bounds) const {
    721   bounds->Inset(SelectValueForShelfAlignment(
    722       gfx::Insets(0, 0, inset, 0),
    723       gfx::Insets(0, inset, 0, 0),
    724       gfx::Insets(0, 0, 0, inset),
    725       gfx::Insets(inset, 0, 0, 0)));
    726 }
    727 
    728 void ShelfLayoutManager::CalculateTargetBounds(
    729     const State& state,
    730     TargetBounds* target_bounds) {
    731   const gfx::Rect available_bounds(GetAvailableBounds());
    732   gfx::Rect status_size(
    733       shelf_->status_area_widget()->GetWindowBoundsInScreen().size());
    734   int shelf_width = 0, shelf_height = 0;
    735   GetShelfSize(&shelf_width, &shelf_height);
    736   if (IsHorizontalAlignment())
    737     shelf_width = available_bounds.width();
    738   else
    739     shelf_height = available_bounds.height();
    740 
    741   if (state.visibility_state == SHELF_AUTO_HIDE &&
    742       state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) {
    743     // Auto-hidden shelf always starts with the default size. If a gesture-drag
    744     // is in progress, then the call to UpdateTargetBoundsForGesture() below
    745     // takes care of setting the height properly.
    746     if (IsHorizontalAlignment())
    747       shelf_height = kAutoHideSize;
    748     else
    749       shelf_width = kAutoHideSize;
    750   } else if (state.visibility_state == SHELF_HIDDEN ||
    751       !keyboard_bounds_.IsEmpty()) {
    752     if (IsHorizontalAlignment())
    753       shelf_height = 0;
    754     else
    755       shelf_width = 0;
    756   }
    757 
    758   target_bounds->shelf_bounds_in_root = SelectValueForShelfAlignment(
    759       gfx::Rect(available_bounds.x(), available_bounds.bottom() - shelf_height,
    760                     available_bounds.width(), shelf_height),
    761       gfx::Rect(available_bounds.x(), available_bounds.y(),
    762                     shelf_width, available_bounds.height()),
    763       gfx::Rect(available_bounds.right() - shelf_width, available_bounds.y(),
    764                     shelf_width, available_bounds.height()),
    765       gfx::Rect(available_bounds.x(), available_bounds.y(),
    766                     available_bounds.width(), shelf_height));
    767 
    768   int status_inset = std::max(0, GetPreferredShelfSize() -
    769       PrimaryAxisValue(status_size.height(), status_size.width()));
    770 
    771   if (ash::switches::UseAlternateShelfLayout()) {
    772     status_inset = 0;
    773     if (IsHorizontalAlignment())
    774       status_size.set_height(kShelfSize);
    775     else
    776       status_size.set_width(kShelfSize);
    777   }
    778 
    779   target_bounds->status_bounds_in_shelf = SelectValueForShelfAlignment(
    780       gfx::Rect(base::i18n::IsRTL() ? 0 : shelf_width - status_size.width(),
    781                     status_inset, status_size.width(), status_size.height()),
    782       gfx::Rect(shelf_width - (status_size.width() + status_inset),
    783                     shelf_height - status_size.height(), status_size.width(),
    784                     status_size.height()),
    785       gfx::Rect(status_inset, shelf_height - status_size.height(),
    786                     status_size.width(), status_size.height()),
    787       gfx::Rect(base::i18n::IsRTL() ? 0 : shelf_width - status_size.width(),
    788                     shelf_height - (status_size.height() + status_inset),
    789                     status_size.width(), status_size.height()));
    790 
    791   target_bounds->work_area_insets = SelectValueForShelfAlignment(
    792       gfx::Insets(0, 0, GetWorkAreaSize(state, shelf_height), 0),
    793       gfx::Insets(0, GetWorkAreaSize(state, shelf_width), 0, 0),
    794       gfx::Insets(0, 0, 0, GetWorkAreaSize(state, shelf_width)),
    795       gfx::Insets(GetWorkAreaSize(state, shelf_height), 0, 0, 0));
    796 
    797   // TODO(varkha): The functionality of managing insets for display areas
    798   // should probably be pushed to a separate component. This would simplify or
    799   // remove entirely the dependency on keyboard and dock.
    800 
    801   // Also push in the work area inset for the keyboard if it is visible.
    802   if (!keyboard_bounds_.IsEmpty()) {
    803     gfx::Insets keyboard_insets(0, 0, keyboard_bounds_.height(), 0);
    804     target_bounds->work_area_insets += keyboard_insets;
    805   }
    806 
    807   // Also push in the work area inset for the dock if it is visible.
    808   if (!dock_bounds_.IsEmpty()) {
    809     gfx::Insets dock_insets(
    810         0, (dock_bounds_.x() > 0 ? 0 : dock_bounds_.width()),
    811         0, (dock_bounds_.x() > 0 ? dock_bounds_.width() : 0));
    812     target_bounds->work_area_insets += dock_insets;
    813   }
    814 
    815   target_bounds->opacity =
    816       (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS ||
    817        state.visibility_state == SHELF_VISIBLE ||
    818        state.visibility_state == SHELF_AUTO_HIDE) ? 1.0f : 0.0f;
    819   target_bounds->status_opacity =
    820       (state.visibility_state == SHELF_AUTO_HIDE &&
    821        state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN &&
    822        gesture_drag_status_ != GESTURE_DRAG_IN_PROGRESS) ?
    823       0.0f : target_bounds->opacity;
    824 
    825   if (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS)
    826     UpdateTargetBoundsForGesture(target_bounds);
    827 
    828   // This needs to happen after calling UpdateTargetBoundsForGesture(), because
    829   // that can change the size of the shelf.
    830   target_bounds->launcher_bounds_in_shelf = SelectValueForShelfAlignment(
    831       gfx::Rect(0, 0,
    832                 shelf_width - status_size.width(),
    833                 target_bounds->shelf_bounds_in_root.height()),
    834       gfx::Rect(0, 0, target_bounds->shelf_bounds_in_root.width(),
    835                 shelf_height - status_size.height()),
    836       gfx::Rect(0, 0, target_bounds->shelf_bounds_in_root.width(),
    837                 shelf_height - status_size.height()),
    838       gfx::Rect(0, 0,
    839                 shelf_width - status_size.width(),
    840                 target_bounds->shelf_bounds_in_root.height()));
    841 }
    842 
    843 void ShelfLayoutManager::UpdateTargetBoundsForGesture(
    844     TargetBounds* target_bounds) const {
    845   CHECK_EQ(GESTURE_DRAG_IN_PROGRESS, gesture_drag_status_);
    846   bool horizontal = IsHorizontalAlignment();
    847   const gfx::Rect& available_bounds(root_window_->bounds());
    848   int resistance_free_region = 0;
    849 
    850   if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_HIDDEN &&
    851       visibility_state() == SHELF_AUTO_HIDE &&
    852       auto_hide_state() != SHELF_AUTO_HIDE_SHOWN) {
    853     // If the shelf was hidden when the drag started (and the state hasn't
    854     // changed since then, e.g. because the tray-menu was shown because of the
    855     // drag), then allow the drag some resistance-free region at first to make
    856     // sure the shelf sticks with the finger until the shelf is visible.
    857     resistance_free_region = GetPreferredShelfSize() - kAutoHideSize;
    858   }
    859 
    860   bool resist = SelectValueForShelfAlignment(
    861       gesture_drag_amount_ < -resistance_free_region,
    862       gesture_drag_amount_ > resistance_free_region,
    863       gesture_drag_amount_ < -resistance_free_region,
    864       gesture_drag_amount_ > resistance_free_region);
    865 
    866   float translate = 0.f;
    867   if (resist) {
    868     float diff = fabsf(gesture_drag_amount_) - resistance_free_region;
    869     diff = std::min(diff, sqrtf(diff));
    870     if (gesture_drag_amount_ < 0)
    871       translate = -resistance_free_region - diff;
    872     else
    873       translate = resistance_free_region + diff;
    874   } else {
    875     translate = gesture_drag_amount_;
    876   }
    877 
    878   if (horizontal) {
    879     // Move and size the launcher with the gesture.
    880     int shelf_height = target_bounds->shelf_bounds_in_root.height() - translate;
    881     shelf_height = std::max(shelf_height, kAutoHideSize);
    882     target_bounds->shelf_bounds_in_root.set_height(shelf_height);
    883     if (GetAlignment() == SHELF_ALIGNMENT_BOTTOM) {
    884       target_bounds->shelf_bounds_in_root.set_y(
    885           available_bounds.bottom() - shelf_height);
    886     }
    887 
    888     if (ash::switches::UseAlternateShelfLayout()) {
    889       target_bounds->status_bounds_in_shelf.set_y(0);
    890     } else {
    891       // The statusbar should be in the center of the shelf.
    892       gfx::Rect status_y = target_bounds->shelf_bounds_in_root;
    893       status_y.set_y(0);
    894       status_y.ClampToCenteredSize(
    895           target_bounds->status_bounds_in_shelf.size());
    896       target_bounds->status_bounds_in_shelf.set_y(status_y.y());
    897     }
    898   } else {
    899     // Move and size the launcher with the gesture.
    900     int shelf_width = target_bounds->shelf_bounds_in_root.width();
    901     bool right_aligned = GetAlignment() == SHELF_ALIGNMENT_RIGHT;
    902     if (right_aligned)
    903       shelf_width -= translate;
    904     else
    905       shelf_width += translate;
    906     shelf_width = std::max(shelf_width, kAutoHideSize);
    907     target_bounds->shelf_bounds_in_root.set_width(shelf_width);
    908     if (right_aligned) {
    909       target_bounds->shelf_bounds_in_root.set_x(
    910           available_bounds.right() - shelf_width);
    911     }
    912 
    913     if (ash::switches::UseAlternateShelfLayout()) {
    914       if (right_aligned)
    915         target_bounds->status_bounds_in_shelf.set_x(0);
    916       else
    917         target_bounds->status_bounds_in_shelf.set_x(
    918             target_bounds->shelf_bounds_in_root.width() -
    919             kShelfSize);
    920     } else {
    921       // The statusbar should be in the center of the shelf.
    922       gfx::Rect status_x = target_bounds->shelf_bounds_in_root;
    923       status_x.set_x(0);
    924       status_x.ClampToCenteredSize(
    925           target_bounds->status_bounds_in_shelf.size());
    926       target_bounds->status_bounds_in_shelf.set_x(status_x.x());
    927     }
    928   }
    929 }
    930 
    931 void ShelfLayoutManager::UpdateShelfBackground(
    932     BackgroundAnimatorChangeType type) {
    933   const ShelfBackgroundType background_type(GetShelfBackgroundType());
    934   shelf_->SetPaintsBackground(background_type, type);
    935   FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
    936                     OnBackgroundUpdated(background_type, type));
    937 }
    938 
    939 ShelfBackgroundType ShelfLayoutManager::GetShelfBackgroundType() const {
    940   if (state_.visibility_state != SHELF_AUTO_HIDE &&
    941       state_.window_state == WORKSPACE_WINDOW_STATE_MAXIMIZED) {
    942     return SHELF_BACKGROUND_MAXIMIZED;
    943   }
    944 
    945   if (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS ||
    946       (!state_.is_screen_locked && window_overlaps_shelf_) ||
    947       (state_.visibility_state == SHELF_AUTO_HIDE)) {
    948     return SHELF_BACKGROUND_OVERLAP;
    949   }
    950 
    951   return SHELF_BACKGROUND_DEFAULT;
    952 }
    953 
    954 void ShelfLayoutManager::UpdateAutoHideStateNow() {
    955   SetState(state_.visibility_state);
    956 
    957   // If the state did not change, the auto hide timer may still be running.
    958   StopAutoHideTimer();
    959 }
    960 
    961 void ShelfLayoutManager::StopAutoHideTimer() {
    962   auto_hide_timer_.Stop();
    963   mouse_over_shelf_when_auto_hide_timer_started_ = false;
    964 }
    965 
    966 gfx::Rect ShelfLayoutManager::GetAutoHideShowShelfRegionInScreen() const {
    967   gfx::Rect shelf_bounds_in_screen = shelf_->GetWindowBoundsInScreen();
    968   gfx::Vector2d offset = SelectValueForShelfAlignment(
    969       gfx::Vector2d(0, shelf_bounds_in_screen.height()),
    970       gfx::Vector2d(-kMaxAutoHideShowShelfRegionSize, 0),
    971       gfx::Vector2d(shelf_bounds_in_screen.width(), 0),
    972       gfx::Vector2d(0, -kMaxAutoHideShowShelfRegionSize));
    973 
    974   gfx::Rect show_shelf_region_in_screen = shelf_bounds_in_screen;
    975   show_shelf_region_in_screen += offset;
    976   if (IsHorizontalAlignment())
    977     show_shelf_region_in_screen.set_height(kMaxAutoHideShowShelfRegionSize);
    978   else
    979     show_shelf_region_in_screen.set_width(kMaxAutoHideShowShelfRegionSize);
    980 
    981   // TODO: Figure out if we need any special handling when the keyboard is
    982   // visible.
    983   return show_shelf_region_in_screen;
    984 }
    985 
    986 ShelfAutoHideState ShelfLayoutManager::CalculateAutoHideState(
    987     ShelfVisibilityState visibility_state) const {
    988   if (visibility_state != SHELF_AUTO_HIDE || !shelf_)
    989     return SHELF_AUTO_HIDE_HIDDEN;
    990 
    991   Shell* shell = Shell::GetInstance();
    992   if (shell->GetAppListTargetVisibility())
    993     return SHELF_AUTO_HIDE_SHOWN;
    994 
    995   if (shelf_->status_area_widget() &&
    996       shelf_->status_area_widget()->ShouldShowLauncher())
    997     return SHELF_AUTO_HIDE_SHOWN;
    998 
    999   if (shelf_->launcher() && shelf_->launcher()->IsShowingMenu())
   1000     return SHELF_AUTO_HIDE_SHOWN;
   1001 
   1002   if (shelf_->launcher() && shelf_->launcher()->IsShowingOverflowBubble())
   1003     return SHELF_AUTO_HIDE_SHOWN;
   1004 
   1005   if (shelf_->IsActive() || shelf_->status_area_widget()->IsActive())
   1006     return SHELF_AUTO_HIDE_SHOWN;
   1007 
   1008   const std::vector<aura::Window*> windows =
   1009       ash::MruWindowTracker::BuildWindowList(false);
   1010 
   1011   // Process the window list and check if there are any visible windows.
   1012   bool visible_window = false;
   1013   for (size_t i = 0; i < windows.size(); ++i) {
   1014     if (windows[i] && windows[i]->IsVisible() &&
   1015         !wm::GetWindowState(windows[i])->IsMinimized() &&
   1016         root_window_ == windows[i]->GetRootWindow()) {
   1017       visible_window = true;
   1018       break;
   1019     }
   1020   }
   1021   // If there are no visible windows do not hide the shelf.
   1022   if (!visible_window)
   1023     return SHELF_AUTO_HIDE_SHOWN;
   1024 
   1025   if (gesture_drag_status_ == GESTURE_DRAG_COMPLETE_IN_PROGRESS)
   1026     return gesture_drag_auto_hide_state_;
   1027 
   1028   // Don't show if the user is dragging the mouse.
   1029   if (auto_hide_event_filter_.get() && auto_hide_event_filter_->in_mouse_drag())
   1030     return SHELF_AUTO_HIDE_HIDDEN;
   1031 
   1032   // Ignore the mouse position if mouse events are disabled.
   1033   aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(
   1034       shelf_->GetNativeWindow()->GetRootWindow());
   1035   if (!cursor_client->IsMouseEventsEnabled())
   1036     return SHELF_AUTO_HIDE_HIDDEN;
   1037 
   1038   gfx::Rect shelf_region = shelf_->GetWindowBoundsInScreen();
   1039   if (shelf_->status_area_widget() &&
   1040       shelf_->status_area_widget()->IsMessageBubbleShown() &&
   1041       IsVisible()) {
   1042     // Increase the the hit test area to prevent the shelf from disappearing
   1043     // when the mouse is over the bubble gap.
   1044     ShelfAlignment alignment = GetAlignment();
   1045     shelf_region.Inset(alignment == SHELF_ALIGNMENT_RIGHT ?
   1046                            -kNotificationBubbleGapHeight : 0,
   1047                        alignment == SHELF_ALIGNMENT_BOTTOM ?
   1048                            -kNotificationBubbleGapHeight : 0,
   1049                        alignment == SHELF_ALIGNMENT_LEFT ?
   1050                            -kNotificationBubbleGapHeight : 0,
   1051                        alignment == SHELF_ALIGNMENT_TOP ?
   1052                            -kNotificationBubbleGapHeight : 0);
   1053   }
   1054 
   1055   gfx::Point cursor_position_in_screen =
   1056       Shell::GetScreen()->GetCursorScreenPoint();
   1057   if (shelf_region.Contains(cursor_position_in_screen))
   1058     return SHELF_AUTO_HIDE_SHOWN;
   1059 
   1060   // When the shelf is auto hidden and the shelf is on the boundary between two
   1061   // displays, it is hard to trigger showing the shelf. For instance, if a
   1062   // user's primary display is left of their secondary display, it is hard to
   1063   // unautohide a left aligned shelf on the secondary display.
   1064   // It is hard because:
   1065   // - It is hard to stop the cursor in the shelf "light bar" and not overshoot.
   1066   // - The cursor is warped to the other display if the cursor gets to the edge
   1067   //   of the display.
   1068   // Show the shelf if the cursor started on the shelf and the user overshot the
   1069   // shelf slightly to make it easier to show the shelf in this situation. We
   1070   // do not check |auto_hide_timer_|.IsRunning() because it returns false when
   1071   // the timer's task is running.
   1072   if ((state_.auto_hide_state == SHELF_AUTO_HIDE_SHOWN ||
   1073        mouse_over_shelf_when_auto_hide_timer_started_) &&
   1074       GetAutoHideShowShelfRegionInScreen().Contains(
   1075           cursor_position_in_screen)) {
   1076     return SHELF_AUTO_HIDE_SHOWN;
   1077   }
   1078 
   1079   return SHELF_AUTO_HIDE_HIDDEN;
   1080 }
   1081 
   1082 void ShelfLayoutManager::UpdateHitTestBounds() {
   1083   gfx::Insets mouse_insets;
   1084   gfx::Insets touch_insets;
   1085   if (state_.visibility_state == SHELF_VISIBLE) {
   1086     // Let clicks at the very top of the launcher through so windows can be
   1087     // resized with the bottom-right corner and bottom edge.
   1088     mouse_insets = GetInsetsForAlignment(kWorkspaceAreaVisibleInset);
   1089   } else if (state_.visibility_state == SHELF_AUTO_HIDE) {
   1090     // Extend the touch hit target out a bit to allow users to drag shelf out
   1091     // while hidden.
   1092     touch_insets = GetInsetsForAlignment(-kWorkspaceAreaAutoHideInset);
   1093   }
   1094 
   1095   if (shelf_ && shelf_->GetNativeWindow())
   1096     shelf_->GetNativeWindow()->SetHitTestBoundsOverrideOuter(mouse_insets,
   1097                                                              touch_insets);
   1098   shelf_->status_area_widget()->GetNativeWindow()->
   1099       SetHitTestBoundsOverrideOuter(mouse_insets, touch_insets);
   1100 }
   1101 
   1102 bool ShelfLayoutManager::IsShelfWindow(aura::Window* window) {
   1103   if (!window)
   1104     return false;
   1105   return (shelf_ && shelf_->GetNativeWindow()->Contains(window)) ||
   1106       (shelf_->status_area_widget() &&
   1107        shelf_->status_area_widget()->GetNativeWindow()->Contains(window));
   1108 }
   1109 
   1110 int ShelfLayoutManager::GetWorkAreaSize(const State& state, int size) const {
   1111   if (state.visibility_state == SHELF_VISIBLE)
   1112     return size;
   1113   if (state.visibility_state == SHELF_AUTO_HIDE)
   1114     return kAutoHideSize;
   1115   return 0;
   1116 }
   1117 
   1118 gfx::Rect ShelfLayoutManager::GetAvailableBounds() const {
   1119   gfx::Rect bounds(root_window_->bounds());
   1120   bounds.set_height(bounds.height() - keyboard_bounds_.height());
   1121   return bounds;
   1122 }
   1123 
   1124 void ShelfLayoutManager::OnKeyboardBoundsChanging(
   1125     const gfx::Rect& keyboard_bounds) {
   1126   keyboard_bounds_ = keyboard_bounds;
   1127   OnWindowResized();
   1128 }
   1129 
   1130 void ShelfLayoutManager::OnDockBoundsChanging(
   1131     const gfx::Rect& dock_bounds,
   1132     DockedWindowLayoutManagerObserver::Reason reason) {
   1133   // Skip shelf layout in case docked notification originates from this class.
   1134   if (reason == DISPLAY_INSETS_CHANGED)
   1135     return;
   1136   if (dock_bounds_ != dock_bounds) {
   1137     dock_bounds_ = dock_bounds;
   1138     OnWindowResized();
   1139     UpdateVisibilityState();
   1140     UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE);
   1141   }
   1142 }
   1143 
   1144 void ShelfLayoutManager::OnLockStateEvent(LockStateObserver::EventType event) {
   1145   if (event == EVENT_LOCK_ANIMATION_STARTED) {
   1146     // Hide the status area widget (using auto hide animation).
   1147     base::AutoReset<ShelfVisibilityState> state(&state_.visibility_state,
   1148                                                 SHELF_HIDDEN);
   1149     TargetBounds target_bounds;
   1150     CalculateTargetBounds(state_, &target_bounds);
   1151     UpdateBoundsAndOpacity(target_bounds, true, NULL);
   1152   }
   1153 }
   1154 
   1155 gfx::Insets ShelfLayoutManager::GetInsetsForAlignment(int distance) const {
   1156   switch (GetAlignment()) {
   1157     case SHELF_ALIGNMENT_BOTTOM:
   1158       return gfx::Insets(distance, 0, 0, 0);
   1159     case SHELF_ALIGNMENT_LEFT:
   1160       return gfx::Insets(0, 0, 0, distance);
   1161     case SHELF_ALIGNMENT_RIGHT:
   1162       return gfx::Insets(0, distance, 0, 0);
   1163     case SHELF_ALIGNMENT_TOP:
   1164       return gfx::Insets(0, 0, distance, 0);
   1165   }
   1166   NOTREACHED();
   1167   return gfx::Insets();
   1168 }
   1169 
   1170 }  // namespace internal
   1171 }  // namespace ash
   1172