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