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
32namespace aura {
33class RootWindow;
34}
35
36namespace ui {
37class GestureEvent;
38class ImplicitAnimationObserver;
39}
40
41namespace ash {
42class PanelLayoutManagerTest;
43class ScreenAsh;
44class ShelfBezelEventFilter;
45class ShelfLayoutManagerObserver;
46class ShelfLayoutManagerTest;
47class ShelfWidget;
48class StatusAreaWidget;
49class WorkspaceController;
50FORWARD_DECLARE_TEST(AshPopupAlignmentDelegateTest, AutoHide);
51FORWARD_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.
59class 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