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