1 // Copyright 2016 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_H_
6 #define ASH_SHELF_SHELF_H_
7 
8 #include <memory>
9 
10 #include "ash/ash_export.h"
11 #include "ash/public/cpp/metrics_util.h"
12 #include "ash/public/cpp/shelf_types.h"
13 #include "ash/shelf/shelf_layout_manager_observer.h"
14 #include "ash/shelf/shelf_locking_manager.h"
15 #include "base/observer_list.h"
16 
17 namespace aura {
18 class Window;
19 }
20 
21 namespace gfx {
22 class Rect;
23 }
24 
25 namespace ui {
26 class GestureEvent;
27 class MouseWheelEvent;
28 class MouseEvent;
29 class ScrollEvent;
30 }  // namespace ui
31 
32 namespace ash {
33 
34 enum class AnimationChangeType;
35 class HotseatWidget;
36 class HotseatWidgetAnimationMetricsReporter;
37 class NavigationWidgetAnimationMetricsReporter;
38 class ShelfFocusCycler;
39 class ShelfLayoutManager;
40 class ShelfLayoutManagerTest;
41 class ShelfLockingManager;
42 class ShelfNavigationWidget;
43 class ShelfView;
44 class ShelfWidget;
45 class StatusAreaWidget;
46 class ShelfObserver;
47 class TrayBackgroundView;
48 class WorkAreaInsets;
49 class ShelfTooltipManager;
50 
51 // Controller for the shelf state. One per display, because each display might
52 // have different shelf alignment, autohide, etc. Exists for the lifetime of the
53 // root window controller.
54 class ASH_EXPORT Shelf : public ShelfLayoutManagerObserver {
55  public:
56   // Used to maintain a lock for the auto-hide shelf. If lock, then we should
57   // not update the state of the auto-hide shelf.
58   class ScopedAutoHideLock {
59    public:
ScopedAutoHideLock(Shelf * shelf)60     explicit ScopedAutoHideLock(Shelf* shelf) : shelf_(shelf) {
61       ++shelf_->auto_hide_lock_;
62     }
~ScopedAutoHideLock()63     ~ScopedAutoHideLock() {
64       --shelf_->auto_hide_lock_;
65       DCHECK_GE(shelf_->auto_hide_lock_, 0);
66     }
67 
68    private:
69     Shelf* shelf_;
70   };
71 
72   Shelf();
73   ~Shelf() override;
74 
75   // Returns the shelf for the display that |window| is on. Note that the shelf
76   // widget may not exist, or the shelf may not be visible.
77   static Shelf* ForWindow(aura::Window* window);
78 
79   // Launch a 0-indexed shelf item in the shelf. A negative index launches the
80   // last shelf item in the shelf.
81   static void LaunchShelfItem(int item_index);
82 
83   // Activates the shelf item specified by the index in the list of shelf items.
84   static void ActivateShelfItem(int item_index);
85 
86   // Activates the shelf item specified by the index in the list of shelf items
87   // on the display identified by |display_id|.
88   static void ActivateShelfItemOnDisplay(int item_index, int64_t display_id);
89 
90   void CreateNavigationWidget(aura::Window* container);
91   void CreateHotseatWidget(aura::Window* container);
92   void CreateStatusAreaWidget(aura::Window* status_container);
93   void CreateShelfWidget(aura::Window* root);
94   void ShutdownShelfWidget();
95   void DestroyShelfWidget();
96 
97   // Returns true if the shelf is visible. Shelf can be visible in 1)
98   // SHELF_VISIBLE or 2) SHELF_AUTO_HIDE but in SHELF_AUTO_HIDE_SHOWN. See
99   // details in ShelfLayoutManager::IsVisible.
100   bool IsVisible() const;
101 
102   // Returns the window showing the shelf.
103   const aura::Window* GetWindow() const;
104   aura::Window* GetWindow();
105 
106   void SetAlignment(ShelfAlignment alignment);
107 
108   // Returns true if the shelf alignment is horizontal (i.e. at the bottom).
109   bool IsHorizontalAlignment() const;
110 
111   // Returns a value based on shelf alignment.
112   template <typename T>
SelectValueForShelfAlignment(T bottom,T left,T right)113   T SelectValueForShelfAlignment(T bottom, T left, T right) const {
114     switch (alignment_) {
115       case ShelfAlignment::kBottom:
116       case ShelfAlignment::kBottomLocked:
117         return bottom;
118       case ShelfAlignment::kLeft:
119         return left;
120       case ShelfAlignment::kRight:
121         return right;
122     }
123     NOTREACHED();
124     return bottom;
125   }
126 
127   // Returns |horizontal| if shelf is horizontal, otherwise |vertical|.
128   template <typename T>
PrimaryAxisValue(T horizontal,T vertical)129   T PrimaryAxisValue(T horizontal, T vertical) const {
130     return IsHorizontalAlignment() ? horizontal : vertical;
131   }
132 
133   void SetAutoHideBehavior(ShelfAutoHideBehavior behavior);
134 
135   ShelfAutoHideState GetAutoHideState() const;
136 
137   // Invoke when the auto-hide state may have changed (for example, when the
138   // system tray bubble opens it should force the shelf to be visible).
139   void UpdateAutoHideState();
140 
141   ShelfBackgroundType GetBackgroundType() const;
142 
143   void UpdateVisibilityState();
144 
145   void MaybeUpdateShelfBackground();
146 
147   ShelfVisibilityState GetVisibilityState() const;
148 
149   gfx::Rect GetShelfBoundsInScreen() const;
150 
151   // Returns the ideal bounds of the shelf assuming it is visible.
152   gfx::Rect GetIdealBounds() const;
153 
154   // Returns the ideal bounds of the shelf, but in tablet mode always returns
155   // the bounds of the in-app shelf.
156   gfx::Rect GetIdealBoundsForWorkAreaCalculation();
157 
158   // Returns the screen bounds of the item for the specified window. If there is
159   // no item for the specified window an empty rect is returned.
160   gfx::Rect GetScreenBoundsOfItemIconForWindow(aura::Window* window);
161 
162   // Handles a gesture |event| coming from a source outside the shelf widget
163   // (e.g. the status area widget). Allows support for behaviors like toggling
164   // auto-hide with a swipe, even if that gesture event hits another window.
165   // Returns true if the event was handled.
166   bool ProcessGestureEvent(const ui::GestureEvent& event);
167 
168   // Handles a mouse |event| coming from the Shelf.
169   void ProcessMouseEvent(const ui::MouseEvent& event);
170 
171   // Handles a scroll |event| coming from the Shelf.
172   void ProcessScrollEvent(ui::ScrollEvent* event);
173 
174   // Handles a mousewheel scroll event coming from the shelf. We use
175   // |from_touchpad| to distinguish if an event originated from a touchpad
176   // scroll or a mousewheel scroll.
177   void ProcessMouseWheelEvent(ui::MouseWheelEvent* event, bool from_touchpad);
178 
179   void AddObserver(ShelfObserver* observer);
180   void RemoveObserver(ShelfObserver* observer);
181 
182   void NotifyShelfIconPositionsChanged();
183   StatusAreaWidget* GetStatusAreaWidget() const;
184 
185   // Get the tray button that the system tray bubble and the notification center
186   // bubble will be anchored. See also: StatusAreaWidget::GetSystemTrayAnchor()
187   TrayBackgroundView* GetSystemTrayAnchorView() const;
188 
189   // Get the anchor rect that the system tray bubble and the notification center
190   // bubble will be anchored.
191   // x() and y() designates anchor point, but width() and height() are dummy.
192   // See also: BubbleDialogDelegateView::GetBubbleBounds()
193   gfx::Rect GetSystemTrayAnchorRect() const;
194 
195   // Returns whether this shelf should be hidden on secondary display in a given
196   // |state|.
197   bool ShouldHideOnSecondaryDisplay(session_manager::SessionState state);
198 
199   void SetVirtualKeyboardBoundsForTesting(const gfx::Rect& bounds);
200   ShelfLockingManager* GetShelfLockingManagerForTesting();
201   ShelfView* GetShelfViewForTesting();
202 
shelf_layout_manager()203   ShelfLayoutManager* shelf_layout_manager() const {
204     return shelf_layout_manager_;
205   }
206 
207   // Getters for the various shelf components.
shelf_widget()208   ShelfWidget* shelf_widget() const { return shelf_widget_.get(); }
navigation_widget()209   ShelfNavigationWidget* navigation_widget() const {
210     return navigation_widget_.get();
211   }
hotseat_widget()212   HotseatWidget* hotseat_widget() const { return hotseat_widget_.get(); }
status_area_widget()213   StatusAreaWidget* status_area_widget() const {
214     return status_area_widget_.get();
215   }
216 
alignment()217   ShelfAlignment alignment() const { return alignment_; }
auto_hide_behavior()218   ShelfAutoHideBehavior auto_hide_behavior() const {
219     return auto_hide_behavior_;
220   }
221 
shelf_focus_cycler()222   ShelfFocusCycler* shelf_focus_cycler() { return shelf_focus_cycler_.get(); }
223 
set_is_tablet_mode_animation_running(bool value)224   void set_is_tablet_mode_animation_running(bool value) {
225     is_tablet_mode_animation_running_ = value;
226   }
is_tablet_mode_animation_running()227   bool is_tablet_mode_animation_running() const {
228     return is_tablet_mode_animation_running_;
229   }
auto_hide_lock()230   int auto_hide_lock() const { return auto_hide_lock_; }
231 
tooltip()232   ShelfTooltipManager* tooltip() { return tooltip_.get(); }
233 
234   // |target_state| is the hotseat state after hotseat transition animation.
235   metrics_util::ReportCallback GetHotseatTransitionReportCallback(
236       HotseatState target_state);
237   metrics_util::ReportCallback GetTranslucentBackgroundReportCallback(
238       HotseatState target_state);
239 
240   metrics_util::ReportCallback GetNavigationWidgetAnimationReportCallback(
241       HotseatState target_hotseat_state);
242 
243  protected:
244   // ShelfLayoutManagerObserver:
245   void WillDeleteShelfLayoutManager() override;
246   void WillChangeVisibilityState(ShelfVisibilityState new_state) override;
247   void OnAutoHideStateChanged(ShelfAutoHideState new_state) override;
248   void OnBackgroundUpdated(ShelfBackgroundType background_type,
249                            AnimationChangeType change_type) override;
250   void OnHotseatStateChanged(HotseatState old_state,
251                              HotseatState new_state) override;
252   void OnWorkAreaInsetsChanged() override;
253 
254  private:
255   class AutoDimEventHandler;
256   class AutoHideEventHandler;
257   friend class DimShelfLayoutManagerTestBase;
258   friend class ShelfLayoutManagerTest;
259 
260   // Uses Auto Dim Event Handler to update the shelf dim state.
261   void DimShelf();
262   void UndimShelf();
263   bool HasDimShelfTimer();
264 
265   // Returns work area insets object for the window with this shelf.
266   WorkAreaInsets* GetWorkAreaInsets() const;
267 
268   // Layout manager for the shelf container window. Instances are constructed by
269   // ShelfWidget and lifetimes are managed by the container windows themselves.
270   ShelfLayoutManager* shelf_layout_manager_ = nullptr;
271 
272   // Pointers to shelf components.
273   std::unique_ptr<ShelfNavigationWidget> navigation_widget_;
274   std::unique_ptr<HotseatWidget> hotseat_widget_;
275   std::unique_ptr<StatusAreaWidget> status_area_widget_;
276   // Null during display teardown, see WindowTreeHostManager::DeleteHost() and
277   // RootWindowController::CloseAllChildWindows().
278   std::unique_ptr<ShelfWidget> shelf_widget_;
279 
280   // These initial values hide the shelf until user preferences are available.
281   ShelfAlignment alignment_ = ShelfAlignment::kBottomLocked;
282   ShelfAutoHideBehavior auto_hide_behavior_ =
283       ShelfAutoHideBehavior::kAlwaysHidden;
284 
285   // Sets shelf alignment to bottom during login and screen lock.
286   ShelfLockingManager shelf_locking_manager_;
287 
288   base::ObserverList<ShelfObserver>::Unchecked observers_;
289 
290   // Forwards mouse and gesture events to ShelfLayoutManager for auto-hide.
291   std::unique_ptr<AutoHideEventHandler> auto_hide_event_handler_;
292 
293   // Forwards mouse and gesture events to ShelfLayoutManager for auto-dim.
294   std::unique_ptr<AutoDimEventHandler> auto_dim_event_handler_;
295 
296   // Hands focus off to different parts of the shelf.
297   std::unique_ptr<ShelfFocusCycler> shelf_focus_cycler_;
298 
299   // Animation metrics reporter for hotseat animations. Owned by the Shelf to
300   // ensure it outlives the Hotseat Widget.
301   std::unique_ptr<HotseatWidgetAnimationMetricsReporter>
302       hotseat_transition_metrics_reporter_;
303 
304   // Metrics reporter for animations of the traslucent background in the
305   // hotseat. Owned by the Shelf to ensure it outlives the Hotseat Widget.
306   std::unique_ptr<HotseatWidgetAnimationMetricsReporter>
307       translucent_background_metrics_reporter_;
308 
309   // Animation metrics reporter for navigation widget animations. Owned by the
310   // Shelf to ensure it outlives the Navigation Widget.
311   std::unique_ptr<NavigationWidgetAnimationMetricsReporter>
312       navigation_widget_metrics_reporter_;
313 
314   // True while the animation to enter or exit tablet mode is running. Sometimes
315   // this value is true when the shelf movements are not actually animating
316   // (animation value = 0.0). This is because this is set to true when we
317   // enter/exit tablet mode but the animation is not started until a shelf
318   // OnBoundsChanged is called because of tablet mode. Use this value to sync
319   // the animation for HomeButton.
320   bool is_tablet_mode_animation_running_ = false;
321 
322   // Used by ScopedAutoHideLock to maintain the state of the lock for auto-hide
323   // shelf.
324   int auto_hide_lock_ = 0;
325 
326   std::unique_ptr<ShelfTooltipManager> tooltip_;
327 
328   DISALLOW_COPY_AND_ASSIGN(Shelf);
329 };
330 
331 }  // namespace ash
332 
333 #endif  // ASH_SHELF_SHELF_H_
334