1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
ash / game_dashboard / game_dashboard_context.h [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_GAME_DASHBOARD_GAME_DASHBOARD_CONTEXT_H_
#define ASH_GAME_DASHBOARD_GAME_DASHBOARD_CONTEXT_H_
#include <memory>
#include <string>
#include "ash/ash_export.h"
#include "ash/game_dashboard/game_dashboard_metrics.h"
#include "ash/wm/window_state_observer.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "ui/events/event_handler.h"
#include "ui/views/view_observer.h"
#include "ui/views/widget/unique_widget_ptr.h"
namespace aura {
class Window;
} // namespace aura
namespace views {
class Widget;
} // namespace views
namespace ash {
class GameDashboardButton;
class GameDashboardButtonRevealController;
class GameDashboardMainMenuCursorHandler;
class GameDashboardMainMenuView;
class GameDashboardToolbarView;
// This class manages Game Dashboard related UI for a given `aura::Window`, and
// its instance is managed by the `GameDashboardController`.
class ASH_EXPORT GameDashboardContext : public ui::EventHandler,
public views::ViewObserver,
public views::WidgetObserver,
public WindowStateObserver {
public:
explicit GameDashboardContext(aura::Window* game_window);
GameDashboardContext(const GameDashboardContext&) = delete;
GameDashboardContext& operator=(const GameDashboardContext&) = delete;
~GameDashboardContext() override;
aura::Window* game_window() { return game_window_.get(); }
const std::string& app_id() const { return app_id_; }
GameDashboardMainMenuView* main_menu_view() { return main_menu_view_; }
base::WeakPtr<GameDashboardContext> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
views::Widget* game_dashboard_button_widget() {
return game_dashboard_button_widget_.get();
}
GameDashboardToolbarSnapLocation toolbar_snap_location() const {
return toolbar_snap_location_;
}
void set_recording_from_main_menu(bool from_main_menu) {
recording_from_main_menu_ = from_main_menu;
}
// Returns true if the main menu is opened. `main_menu_widget_` is created
// only when the main menu is opened, otherwise it's null.
bool IsMainMenuOpen() const { return main_menu_widget_.get(); }
const std::u16string& GetRecordingDuration() const;
// Initializes the context. Creates and starts showing the Game Dashboard
// button. Also shows the welcome dialog, if
// `prefs::kGameDashboardShowWelcomeDialog` is true. Separating this logic
// ensures the constructor never references the context created before the
// instance is assigned. Note that this logic should be called once the
// context is created.
void Initialize();
// Stacks Game Dashboard UI widgets above `widget` if it is needed.
void MaybeStackAboveWidget(views::Widget* widget);
// Enables the Game Dashboard widgets' UI visibility if `enable` is true.
// Otherwise, hides the widgets, and uses `main_menu_toggle_method` to
// conditionally hide the toolbar.
void EnableFeatures(
bool enable,
GameDashboardMainMenuToggleMethod main_menu_toggle_method);
// Reassigns the new `toolbar_snap_location_` and performs an animation as the
// toolbar moves to its new location.
void SetGameDashboardToolbarSnapLocation(
GameDashboardToolbarSnapLocation new_location);
// Called by `GameDashboardController` when the game window bounds change.
// `from_animation` is true when window bounds are changing due to an
// animation.
void OnWindowBoundsChanged(bool from_animation);
// Updates for Game Controls flags.
void UpdateForGameControlsFlags();
// Toggles the creation/deletion of the main menu within the game window.
void ToggleMainMenuByAccelerator();
void ToggleMainMenu(GameDashboardMainMenuToggleMethod toggle_method);
// Closes the main menu. Clears `main_menu_widget_` and `main_menu_view_`.
void CloseMainMenu(GameDashboardMainMenuToggleMethod toggle_method);
// Toggles the creation/deletion of the toolbar within the game window.
// Returns the toolbar visibility state.
bool ToggleToolbar();
// Closes the toolbar. Clears `toolbar_widget_` and `toolbar_view_`.
void CloseToolbar();
// Conditionally, updates the toolbar widget's bounds and location, relative
// to the `game_window_`.
void MaybeUpdateToolbarWidgetBounds();
bool IsToolbarVisible() const;
// Returns the toolbar bounds if `IsToolbarVisible`, otherwise an empty rect.
gfx::Rect GetToolbarBoundsInScreen() const;
// Called only when `CaptureModeController` has started a recording session.
// If `is_recording_game_window` is true, then the recording session was
// initiated by the Game Dashboard and the `game_window_` is being recorded.
void OnRecordingStarted(bool is_recording_game_window);
// Called only when `CaptureModeController` has ended a recording session or
// if the recording session was aborted.
void OnRecordingEnded();
// Called when a recorded file has been finalized and fully saved, at which
// point a new recording is allowed to be started.
void OnVideoFileFinalized();
// Controls the Game Dashboard Button visibility.
void SetGameDashboardButtonVisibility(bool visible);
// Controls the Toolbar widget visibility.
void SetToolbarVisibility(bool visible);
// Conditionally, adds this context to the pre-target handler if it hasn't
// already been added.
void MaybeAddPreTargetHandler();
// Conditionally, removes this context from the pre-target handler if it
// hasn't already been removed.
void MaybeRemovePreTargetHandler();
// ui::EventHandler:
void OnEvent(ui::Event* event) override;
// views::ViewObserver:
void OnViewPreferredSizeChanged(views::View* observed_view) override;
// views::WidgetObserver:
void OnWidgetDestroyed(views::Widget* widget) override;
// WindowStateObserver:
void OnPreWindowStateTypeChange(WindowState* window_state,
chromeos::WindowStateType old_type) override;
void OnPostWindowStateTypeChange(WindowState* window_state,
chromeos::WindowStateType old_type) override;
private:
friend class GameDashboardContextTestApi;
// Registers a pretarget handler to always show the mouse cursor. Called when
// the user opens the main menu.
void AddCursorHandler();
// Unregisters the pretarget handler that always shows the mouse cursor.
// Called when the user closes the main menu.
void RemoveCursorHandler();
// Creates a Game Dashboard button widget and adds it as a sibling of the game
// window.
void CreateAndAddGameDashboardButtonWidget();
// Updates the Game Dashboard button widget's bounds and location, relative to
// the `game_window_`.
void UpdateGameDashboardButtonWidgetBounds();
// Called when `GameDashboardButton` is pressed, and toggles the main menu.
void OnGameDashboardButtonPressed();
// Shows the Game Dashboard welcome dialog, if it's enabled in the Game
// Dashboard settings.
void MaybeShowWelcomeDialog();
// Updates the Game Dashboard welcome dialog's bounds and location, relative
// to the `game_window_`.
void MaybeUpdateWelcomeDialogBounds();
// Determines the toolbar's physical location on screen based on the
// `toolbar_snap_location_` value.
const gfx::Rect CalculateToolbarWidgetBounds();
// Updates the toolbar widget's bounds and location utilizing an animation as
// it transfers from the previous location.
void AnimateToolbarWidgetBoundsChange(const gfx::Rect& target_screen_bounds);
// Shows the Game Dashboard toolbar if `prefs::kGameDashboardShowToolbar` is
// true.
void MaybeShowToolbar();
// Repeating timer callback that notifies `main_menu_view_` of the video
// recording session duration.
void OnUpdateRecordingTimer();
// Closes and deletes the Game Dashboard welcome dialog. After closing the
// dialog, if `show_toolbar` is true, call `MaybeShowToolbar`.
void CloseWelcomeDialogIfAny(bool show_toolbar = true);
// Callback when the `GameDashboardWelcomeDialog`'s timer has completed.
void OnWelcomeDialogTimerCompleted();
// Resets the `main_menu_view_`, removes the cursor handler, and updates the
// `game_dashboard_button_` UI.
void UpdateOnMainMenuClosed();
// Ensures that the main menu stacks above the toolbar.
void EnsureMainMenuAboveToolbar();
// Determines whether it's required to tab navigate from one Game Dashboard
// widget to another widget. Returns false if tab-navigating within the same
// widget.
bool ShouldNavigateToNewWidget(const ui::KeyEvent* event) const;
// Returns a list of visible Game Dashboard widgets that are available to be
// traversed.
std::vector<views::Widget*> GetTraversableWidgets() const;
// Manually moves focus to the `new_widget`. If `reverse` is true, focus will
// move backwards.
void MoveFocus(views::Widget* new_widget, ui::Event* event, bool reverse);
const raw_ptr<aura::Window> game_window_;
const std::string app_id_;
// Game Dashboard button widget for the Game Dashboard.
std::unique_ptr<views::Widget> game_dashboard_button_widget_;
// Delegate responsible for determining when to show/hide the Game Dashboard
// button when `game_window_` is in fullscreen. This a temporary scoped
// object that is around while `game_window_` is fullscreen.
std::unique_ptr<GameDashboardButtonRevealController>
game_dashboard_button_reveal_controller_;
// Expanded main menu for the Game Dashboard, which displays the main menu and
// the settings view.
views::UniqueWidgetPtr main_menu_widget_;
// The toolbar for the Game Dashboard.
std::unique_ptr<views::Widget> toolbar_widget_;
// The dialog displayed when the game window first opens.
std::unique_ptr<views::Widget> welcome_dialog_widget_;
// The indicator of the current corner that the toolbar is placed.
GameDashboardToolbarSnapLocation toolbar_snap_location_;
// The `GameDashboardButton` view in the `game_dashboard_button_widget_`.
// Owned by the views hierarchy.
raw_ptr<GameDashboardButton> game_dashboard_button_ = nullptr;
// The `GameDashboardMainMenuView` when the user presses the Game Dashboard
// button to display all Game Dashboard views. This displays the main menu and
// settings views. Owned by the views hierarchy.
raw_ptr<GameDashboardMainMenuView, DanglingUntriaged> main_menu_view_ =
nullptr;
// The `GameDashboardToolbarView` when the user makes the toolbar visible.
// Owned by the views hierarchy.
raw_ptr<GameDashboardToolbarView> toolbar_view_ = nullptr;
// Handles cursor management when the main menu is open.
std::unique_ptr<GameDashboardMainMenuCursorHandler> main_menu_cursor_handler_;
// A repeating timer to keep track of the recording session duration.
base::RepeatingTimer recording_timer_;
// Start time of when `recording_timer_` started.
base::Time recording_start_time_;
// Duration since `recording_timer_` started.
std::u16string recording_duration_;
// Indicates whether the Game Dashboard welcome dialog should be shown. This
// param ensures the welcome dialog is only shown once per game window
// startup.
bool show_welcome_dialog_ = false;
// Indicates where the recording feature starts from the main menu. It is
// false if the recording starts from the toolbar. It is null if the recording
// is started from somewhere else.
std::optional<bool> recording_from_main_menu_;
// Indicates whether this context has been added as a Shell's pre-target
// handler. This param ensures this context isn't added as a pre-target
// handler multiple times.
bool added_to_pre_target_handler_ = false;
base::ScopedObservation<WindowState, WindowStateObserver>
window_state_observation_{this};
base::WeakPtrFactory<GameDashboardContext> weak_ptr_factory_{this};
};
} // namespace ash
#endif // ASH_GAME_DASHBOARD_GAME_DASHBOARD_CONTEXT_H_