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 #ifndef ASH_SHELF_SHELF_LAYOUT_MANAGER_H_
      6 #define ASH_SHELF_SHELF_LAYOUT_MANAGER_H_
      7 
      8 #include <vector>
      9 
     10 #include "ash/ash_export.h"
     11 #include "ash/launcher/launcher.h"
     12 #include "ash/shelf/background_animator.h"
     13 #include "ash/shelf/shelf_types.h"
     14 #include "ash/shell_observer.h"
     15 #include "ash/system/status_area_widget.h"
     16 #include "ash/wm/dock/docked_window_layout_manager_observer.h"
     17 #include "ash/wm/lock_state_observer.h"
     18 #include "ash/wm/workspace/workspace_types.h"
     19 #include "base/basictypes.h"
     20 #include "base/compiler_specific.h"
     21 #include "base/logging.h"
     22 #include "base/observer_list.h"
     23 #include "base/timer/timer.h"
     24 #include "ui/aura/client/activation_change_observer.h"
     25 #include "ui/aura/layout_manager.h"
     26 #include "ui/gfx/insets.h"
     27 #include "ui/gfx/rect.h"
     28 #include "ui/keyboard/keyboard_controller.h"
     29 #include "ui/keyboard/keyboard_controller_observer.h"
     30 
     31 namespace aura {
     32 class RootWindow;
     33 }
     34 
     35 namespace ui {
     36 class GestureEvent;
     37 class ImplicitAnimationObserver;
     38 }
     39 
     40 namespace ash {
     41 class ScreenAsh;
     42 class ShelfLayoutManagerObserver;
     43 class ShelfWidget;
     44 FORWARD_DECLARE_TEST(WebNotificationTrayTest, PopupAndFullscreen);
     45 
     46 namespace internal {
     47 
     48 class PanelLayoutManagerTest;
     49 class ShelfBezelEventFilter;
     50 class ShelfLayoutManagerTest;
     51 class StatusAreaWidget;
     52 class WorkspaceController;
     53 
     54 // ShelfLayoutManager is the layout manager responsible for the launcher and
     55 // status widgets. The launcher is given the total available width and told the
     56 // width of the status area. This allows the launcher to draw the background and
     57 // layout to the status area.
     58 // To respond to bounds changes in the status area StatusAreaLayoutManager works
     59 // closely with ShelfLayoutManager.
     60 class ASH_EXPORT ShelfLayoutManager :
     61     public aura::LayoutManager,
     62     public ash::ShellObserver,
     63     public aura::client::ActivationChangeObserver,
     64     public DockedWindowLayoutManagerObserver,
     65     public keyboard::KeyboardControllerObserver,
     66     public LockStateObserver {
     67  public:
     68 
     69   // We reserve a small area on the edge of the workspace area to ensure that
     70   // the resize handle at the edge of the window can be hit.
     71   static const int kWorkspaceAreaVisibleInset;
     72 
     73   // When autohidden we extend the touch hit target onto the screen so that the
     74   // user can drag the shelf out.
     75   static const int kWorkspaceAreaAutoHideInset;
     76 
     77   // Size of the shelf when auto-hidden.
     78   static const int kAutoHideSize;
     79 
     80   // The size of the shelf when shown (currently only used in alternate
     81   // settings see ash::switches::UseAlternateShelfLayout).
     82   static const int kShelfSize;
     83 
     84   // Inset between the inner edge of the shelf (towards centre of screen), and
     85   // the launcher items, notifications, status area etc.
     86   static const int kShelfItemInset;
     87 
     88   // Returns the preferred size for the shelf (either kLauncherPreferredSize or
     89   // kShelfSize).
     90   static int GetPreferredShelfSize();
     91 
     92   explicit ShelfLayoutManager(ShelfWidget* shelf);
     93   virtual ~ShelfLayoutManager();
     94 
     95   // Sets the ShelfAutoHideBehavior. See enum description for details.
     96   void SetAutoHideBehavior(ShelfAutoHideBehavior behavior);
     97   ShelfAutoHideBehavior auto_hide_behavior() const {
     98     return auto_hide_behavior_;
     99   }
    100 
    101   // Sets the alignment. Returns true if the alignment is changed. Otherwise,
    102   // returns false.
    103   bool SetAlignment(ShelfAlignment alignment);
    104   // Returns the desired alignment for the current state, either the user's
    105   // set alignment (alignment_) or SHELF_ALIGNMENT_BOTTOM when the screen
    106   // is locked.
    107   ShelfAlignment GetAlignment() const;
    108 
    109   void set_workspace_controller(WorkspaceController* controller) {
    110     workspace_controller_ = controller;
    111   }
    112 
    113   bool updating_bounds() const { return updating_bounds_; }
    114 
    115   // Clears internal data for shutdown process.
    116   void PrepareForShutdown();
    117 
    118   // Returns whether the shelf and its contents (launcher, status) are visible
    119   // on the screen.
    120   bool IsVisible() const;
    121 
    122   // Returns the ideal bounds of the shelf assuming it is visible.
    123   gfx::Rect GetIdealBounds();
    124 
    125   // Returns the docked area bounds.
    126   const gfx::Rect& dock_bounds() const { return dock_bounds_; }
    127 
    128   // Stops any animations and sets the bounds of the launcher and status
    129   // widgets.
    130   void LayoutShelf();
    131 
    132   // Returns shelf visibility state based on current value of auto hide
    133   // behavior setting.
    134   ShelfVisibilityState CalculateShelfVisibility();
    135 
    136   // Updates the visibility state.
    137   void UpdateVisibilityState();
    138 
    139   // Invoked by the shelf/launcher when the auto-hide state may have changed.
    140   void UpdateAutoHideState();
    141 
    142   ShelfVisibilityState visibility_state() const {
    143     return state_.visibility_state;
    144   }
    145   ShelfAutoHideState auto_hide_state() const { return state_.auto_hide_state; }
    146 
    147   ShelfWidget* shelf_widget() { return shelf_; }
    148 
    149   // Sets whether any windows overlap the shelf. If a window overlaps the shelf
    150   // the shelf renders slightly differently.
    151   void SetWindowOverlapsShelf(bool value);
    152   bool window_overlaps_shelf() const { return window_overlaps_shelf_; }
    153 
    154   void AddObserver(ShelfLayoutManagerObserver* observer);
    155   void RemoveObserver(ShelfLayoutManagerObserver* observer);
    156 
    157   // Gesture dragging related functions:
    158   void StartGestureDrag(const ui::GestureEvent& gesture);
    159   enum DragState {
    160     DRAG_SHELF,
    161     DRAG_TRAY
    162   };
    163   // Returns DRAG_SHELF if the gesture should continue to drag the entire shelf.
    164   // Returns DRAG_TRAY if the gesture can start dragging the tray-bubble from
    165   // this point on.
    166   DragState UpdateGestureDrag(const ui::GestureEvent& gesture);
    167   void CompleteGestureDrag(const ui::GestureEvent& gesture);
    168   void CancelGestureDrag();
    169 
    170   // Overridden from aura::LayoutManager:
    171   virtual void OnWindowResized() OVERRIDE;
    172   virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE;
    173   virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE;
    174   virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE;
    175   virtual void OnChildWindowVisibilityChanged(aura::Window* child,
    176                                               bool visible) OVERRIDE;
    177   virtual void SetChildBounds(aura::Window* child,
    178                               const gfx::Rect& requested_bounds) OVERRIDE;
    179 
    180   // Overridden from ash::ShellObserver:
    181   virtual void OnLockStateChanged(bool locked) OVERRIDE;
    182 
    183   // Overriden from aura::client::ActivationChangeObserver:
    184   virtual void OnWindowActivated(aura::Window* gained_active,
    185                                  aura::Window* lost_active) OVERRIDE;
    186 
    187   // Overridden from ash::LockStateObserver:
    188   virtual void OnLockStateEvent(LockStateObserver::EventType event) OVERRIDE;
    189 
    190   // TODO(harrym|oshima): These templates will be moved to
    191   // new Shelf class.
    192   // A helper function that provides a shortcut for choosing
    193   // values specific to a shelf alignment.
    194   template<typename T>
    195   T SelectValueForShelfAlignment(T bottom, T left, T right, T top) const {
    196     switch (GetAlignment()) {
    197       case SHELF_ALIGNMENT_BOTTOM:
    198         return bottom;
    199       case SHELF_ALIGNMENT_LEFT:
    200         return left;
    201       case SHELF_ALIGNMENT_RIGHT:
    202         return right;
    203       case SHELF_ALIGNMENT_TOP:
    204         return top;
    205     }
    206     NOTREACHED();
    207     return right;
    208   }
    209 
    210   template<typename T>
    211   T PrimaryAxisValue(T horizontal, T vertical) const {
    212     return IsHorizontalAlignment() ? horizontal : vertical;
    213   }
    214 
    215   // Is the shelf's alignment horizontal?
    216   bool IsHorizontalAlignment() const;
    217 
    218   // Returns a ShelfLayoutManager on the display which has a launcher for
    219   // given |window|. See RootWindowController::ForLauncher for more info.
    220   static ShelfLayoutManager* ForLauncher(aura::Window* window);
    221 
    222  private:
    223   class AutoHideEventFilter;
    224   class UpdateShelfObserver;
    225   friend class ash::ScreenAsh;
    226   friend class PanelLayoutManagerTest;
    227   friend class ShelfLayoutManagerTest;
    228   FRIEND_TEST_ALL_PREFIXES(ash::WebNotificationTrayTest, PopupAndFullscreen);
    229 
    230   struct TargetBounds {
    231     TargetBounds();
    232     ~TargetBounds();
    233 
    234     float opacity;
    235     float status_opacity;
    236     gfx::Rect shelf_bounds_in_root;
    237     gfx::Rect launcher_bounds_in_shelf;
    238     gfx::Rect status_bounds_in_shelf;
    239     gfx::Insets work_area_insets;
    240   };
    241 
    242   struct State {
    243     State() : visibility_state(SHELF_VISIBLE),
    244               auto_hide_state(SHELF_AUTO_HIDE_HIDDEN),
    245               window_state(WORKSPACE_WINDOW_STATE_DEFAULT),
    246               is_screen_locked(false) {}
    247 
    248     // Returns true if the two states are considered equal. As
    249     // |auto_hide_state| only matters if |visibility_state| is
    250     // |SHELF_AUTO_HIDE|, Equals() ignores the |auto_hide_state| as
    251     // appropriate.
    252     bool Equals(const State& other) const {
    253       return other.visibility_state == visibility_state &&
    254           (visibility_state != SHELF_AUTO_HIDE ||
    255            other.auto_hide_state == auto_hide_state) &&
    256           other.window_state == window_state &&
    257           other.is_screen_locked == is_screen_locked;
    258     }
    259 
    260     ShelfVisibilityState visibility_state;
    261     ShelfAutoHideState auto_hide_state;
    262     WorkspaceWindowState window_state;
    263     bool is_screen_locked;
    264   };
    265 
    266   // Sets the visibility of the shelf to |state|.
    267   void SetState(ShelfVisibilityState visibility_state);
    268 
    269   // Updates the bounds and opacity of the launcher and status widgets.
    270   // If |observer| is specified, it will be called back when the animations, if
    271   // any, are complete.
    272   void UpdateBoundsAndOpacity(const TargetBounds& target_bounds,
    273                               bool animate,
    274                               ui::ImplicitAnimationObserver* observer);
    275 
    276   // Stops any animations and progresses them to the end.
    277   void StopAnimating();
    278 
    279   // Returns the width (if aligned to the side) or height (if aligned to the
    280   // bottom).
    281   void GetShelfSize(int* width, int* height);
    282 
    283   // Insets |bounds| by |inset| on the edge the shelf is aligned to.
    284   void AdjustBoundsBasedOnAlignment(int inset, gfx::Rect* bounds) const;
    285 
    286   // Calculates the target bounds assuming visibility of |visible|.
    287   void CalculateTargetBounds(const State& state, TargetBounds* target_bounds);
    288 
    289   // Updates the target bounds if a gesture-drag is in progress. This is only
    290   // used by |CalculateTargetBounds()|.
    291   void UpdateTargetBoundsForGesture(TargetBounds* target_bounds) const;
    292 
    293   // Updates the background of the shelf.
    294   void UpdateShelfBackground(BackgroundAnimatorChangeType type);
    295 
    296   // Returns how the shelf background is painted.
    297   ShelfBackgroundType GetShelfBackgroundType() const;
    298 
    299   // Updates the auto hide state immediately.
    300   void UpdateAutoHideStateNow();
    301 
    302   // Stops the auto hide timer and clears
    303   // |mouse_over_shelf_when_auto_hide_timer_started_|.
    304   void StopAutoHideTimer();
    305 
    306   // Returns the bounds of an additional region which can trigger showing the
    307   // shelf. This region exists to make it easier to trigger showing the shelf
    308   // when the shelf is auto hidden and the shelf is on the boundary between
    309   // two displays.
    310   gfx::Rect GetAutoHideShowShelfRegionInScreen() const;
    311 
    312   // Returns the AutoHideState. This value is determined from the launcher and
    313   // tray.
    314   ShelfAutoHideState CalculateAutoHideState(
    315       ShelfVisibilityState visibility_state) const;
    316 
    317   // Updates the hit test bounds override for launcher and status area.
    318   void UpdateHitTestBounds();
    319 
    320   // Returns true if |window| is a descendant of the shelf.
    321   bool IsShelfWindow(aura::Window* window);
    322 
    323   int GetWorkAreaSize(const State& state, int size) const;
    324 
    325   // Return the bounds available in the parent, taking into account the bounds
    326   // of the keyboard if necessary.
    327   gfx::Rect GetAvailableBounds() const;
    328 
    329   // Overridden from keyboard::KeyboardControllerObserver:
    330   virtual void OnKeyboardBoundsChanging(
    331       const gfx::Rect& keyboard_bounds) OVERRIDE;
    332 
    333   // Overridden from DockedWindowLayoutManagerObserver:
    334   virtual void OnDockBoundsChanging(
    335       const gfx::Rect& dock_bounds,
    336       DockedWindowLayoutManagerObserver::Reason reason) OVERRIDE;
    337 
    338   // Generates insets for inward edge based on the current shelf alignment.
    339   gfx::Insets GetInsetsForAlignment(int distance) const;
    340 
    341   // The RootWindow is cached so that we don't invoke Shell::GetInstance() from
    342   // our destructor. We avoid that as at the time we're deleted Shell is being
    343   // deleted too.
    344   aura::Window* root_window_;
    345 
    346   // True when inside UpdateBoundsAndOpacity() method. Used to prevent calling
    347   // UpdateBoundsAndOpacity() again from SetChildBounds().
    348   bool updating_bounds_;
    349 
    350   // See description above setter.
    351   ShelfAutoHideBehavior auto_hide_behavior_;
    352 
    353   // See description above getter.
    354   ShelfAlignment alignment_;
    355 
    356   // Current state.
    357   State state_;
    358 
    359   ShelfWidget* shelf_;
    360 
    361   WorkspaceController* workspace_controller_;
    362 
    363   // Do any windows overlap the shelf? This is maintained by WorkspaceManager.
    364   bool window_overlaps_shelf_;
    365 
    366   base::OneShotTimer<ShelfLayoutManager> auto_hide_timer_;
    367 
    368   // Whether the mouse was over the shelf when the auto hide timer started.
    369   // False when neither the auto hide timer nor the timer task are running.
    370   bool mouse_over_shelf_when_auto_hide_timer_started_;
    371 
    372   // EventFilter used to detect when user moves the mouse over the launcher to
    373   // trigger showing the launcher.
    374   scoped_ptr<AutoHideEventFilter> auto_hide_event_filter_;
    375 
    376   // EventFilter used to detect when user issues a gesture on a bezel sensor.
    377   scoped_ptr<ShelfBezelEventFilter> bezel_event_filter_;
    378 
    379   ObserverList<ShelfLayoutManagerObserver> observers_;
    380 
    381   // The shelf reacts to gesture-drags, and can be set to auto-hide for certain
    382   // gestures. Some shelf behaviour (e.g. visibility state, background color
    383   // etc.) are affected by various stages of the drag. The enum keeps track of
    384   // the present status of the gesture drag.
    385   enum GestureDragStatus {
    386     GESTURE_DRAG_NONE,
    387     GESTURE_DRAG_IN_PROGRESS,
    388     GESTURE_DRAG_CANCEL_IN_PROGRESS,
    389     GESTURE_DRAG_COMPLETE_IN_PROGRESS
    390   };
    391   GestureDragStatus gesture_drag_status_;
    392 
    393   // Tracks the amount of the drag. The value is only valid when
    394   // |gesture_drag_status_| is set to GESTURE_DRAG_IN_PROGRESS.
    395   float gesture_drag_amount_;
    396 
    397   // Manage the auto-hide state during the gesture.
    398   ShelfAutoHideState gesture_drag_auto_hide_state_;
    399 
    400   // Used to delay updating shelf background.
    401   UpdateShelfObserver* update_shelf_observer_;
    402 
    403   // The bounds of the keyboard.
    404   gfx::Rect keyboard_bounds_;
    405 
    406   // The bounds of the dock.
    407   gfx::Rect dock_bounds_;
    408 
    409   DISALLOW_COPY_AND_ASSIGN(ShelfLayoutManager);
    410 };
    411 
    412 }  // namespace internal
    413 }  // namespace ash
    414 
    415 #endif  // ASH_SHELF_SHELF_LAYOUT_MANAGER_H_
    416