| // 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_CONTROLLER_H_ |
| #define ASH_GAME_DASHBOARD_GAME_DASHBOARD_CONTROLLER_H_ |
| |
| #include <map> |
| #include <memory> |
| |
| #include "ash/ash_export.h" |
| #include "ash/capture_mode/capture_mode_observer.h" |
| #include "ash/game_dashboard/game_dashboard_context.h" |
| #include "ash/game_dashboard/game_dashboard_delegate.h" |
| #include "ash/game_dashboard/game_dashboard_metrics.h" |
| #include "ash/wm/overview/overview_observer.h" |
| #include "base/scoped_multi_source_observation.h" |
| #include "base/scoped_observation.h" |
| #include "ui/aura/env.h" |
| #include "ui/aura/env_observer.h" |
| #include "ui/aura/window_observer.h" |
| #include "ui/display/display_observer.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/wm/public/activation_change_observer.h" |
| |
| class PrefRegistrySimple; |
| |
| namespace aura { |
| class Window; |
| class WindowTracker; |
| } // namespace aura |
| |
| namespace display { |
| enum class TabletState; |
| } // namespace display |
| |
| namespace ash { |
| |
| // Controls the Game Dashboard behavior on supported windows. |
| class ASH_EXPORT GameDashboardController : public aura::EnvObserver, |
| public aura::WindowObserver, |
| public CaptureModeObserver, |
| public display::DisplayObserver, |
| public OverviewObserver, |
| public wm::ActivationChangeObserver { |
| public: |
| explicit GameDashboardController( |
| std::unique_ptr<GameDashboardDelegate> delegate); |
| GameDashboardController(const GameDashboardController&) = delete; |
| GameDashboardController& operator=(const GameDashboardController&) = delete; |
| ~GameDashboardController() override; |
| |
| // Returns the singleton instance owned by `Shell`. |
| static GameDashboardController* Get(); |
| |
| // Checks whether the `window` is a game. |
| static bool IsGameWindow(aura::Window* window); |
| |
| // Checks whether the `window` can respond to accelerator commands. |
| static bool ReadyForAccelerator(aura::Window* window); |
| |
| // Registers preferences used by this class in the provided `registry`. |
| static void RegisterProfilePrefs(PrefRegistrySimple* registry); |
| |
| // Gets the app name by `app_id`. |
| std::string GetArcAppName(const std::string& app_id) const; |
| |
| GameDashboardContext* active_recording_context() { |
| return active_recording_context_; |
| } |
| |
| // Returns a pointer to the `GameDashboardContext` if the given `window` is a |
| // game window, otherwise nullptr. |
| GameDashboardContext* GetGameDashboardContext(aura::Window* window) const; |
| |
| // Stacks all of the `window`'s Game Dashboard widgets on top of `widget`. |
| void MaybeStackAboveWidget(aura::Window* window, views::Widget* widget); |
| |
| // Represents the start of the `context`'s game window capture session. |
| // Sets `context` as the `active_recording_context_`, and requests |
| // `CaptureModeController` to start a capture session for the `context`'s game |
| // window. The session ends when `OnRecordingEnded` or |
| // `OnRecordingStartAborted` is called. |
| void StartCaptureSession(GameDashboardContext* context); |
| |
| // Shows the compat mode resize toggle menu for the given `window`. |
| void ShowResizeToggleMenu(aura::Window* window); |
| |
| // Gets the UKM source id by `app_id`. |
| ukm::SourceId GetUkmSourceId(const std::string& app_id) const; |
| |
| // aura::EnvObserver: |
| void OnWindowInitialized(aura::Window* new_window) override; |
| |
| // aura::WindowObserver: |
| void OnWindowPropertyChanged(aura::Window* window, |
| const void* key, |
| intptr_t old) override; |
| void OnWindowParentChanged(aura::Window* window, |
| aura::Window* parent) override; |
| void OnWindowBoundsChanged(aura::Window* window, |
| const gfx::Rect& old_bounds, |
| const gfx::Rect& new_bounds, |
| ui::PropertyChangeReason reason) override; |
| void OnWindowDestroying(aura::Window* window) override; |
| |
| // CaptureModeObserver: |
| void OnRecordingStarted(aura::Window* current_root) override; |
| void OnRecordingEnded() override; |
| void OnVideoFileFinalized(bool user_deleted_video_file, |
| const gfx::ImageSkia& thumbnail) override; |
| void OnRecordedWindowChangingRoot(aura::Window* new_root) override; |
| void OnRecordingStartAborted() override; |
| |
| // display::DisplayObserver: |
| void OnDisplayTabletStateChanged(display::TabletState state) override; |
| |
| // OverviewObserver: |
| void OnOverviewModeWillStart() override; |
| void OnOverviewModeEnded() override; |
| |
| // wm::ActivationChangeObserver: |
| void OnWindowActivated(wm::ActivationChangeObserver::ActivationReason reason, |
| aura::Window* gained_active, |
| aura::Window* lost_active) override; |
| |
| private: |
| friend class GameDashboardControllerTest; |
| friend class GameDashboardTestBase; |
| |
| enum class WindowGameState { kGame, kNotGame, kNotYetKnown }; |
| |
| using GetWindowStateCallback = base::OnceCallback<void(WindowGameState)>; |
| |
| // Creates a `GameDashboardContext` for the given `window` and |
| // adds it to `game_window_contexts_`, if `GameDashboardContext` doesn't |
| // exist, the given window is a game, the `window` is parented, and the |
| // `window` has a valid `WindowState`. Otherwise, no object is created. |
| void MaybeCreateGameDashboardContext(aura::Window* window); |
| |
| // Checks whether the given window is a game, and then calls |
| // `RefreshWindowTracking`. If there's not enough information, it passes |
| // `kNotYetKnown`, otherwise `kGame` or `kNotGame`, as the `game_state`. |
| void GetWindowGameState(aura::Window* window); |
| |
| // Callback when `GetWindowGameState` calls `GameDashboardDelegate` to |
| // retrieve the app category for the given window in `window_tracker`. |
| // This function calls `RefreshWindowTracking`, as long as the window has not |
| // been destroyed. |
| void OnArcWindowIsGame(std::unique_ptr<aura::WindowTracker> window_tracker, |
| bool is_game); |
| |
| // Updates the window observation, dependent on `game_state`. |
| void RefreshWindowTracking(aura::Window* window, WindowGameState game_state); |
| |
| // Updates the Game Dashboard button state and toolbar for a game window. |
| void RefreshForGameControlsFlags(aura::Window* window); |
| |
| // Enables or disables feature entry partially depending on `enable`. In |
| // addition, it needs to check |
| // `game_dashboard_utils::ShouldEnableFeatures()`. It may close main menu |
| // by `main_menu_toggle_method` when disabling the features. |
| void MaybeEnableFeatures( |
| bool enable, |
| GameDashboardMainMenuToggleMethod main_menu_toggle_method); |
| |
| std::map<aura::Window*, std::unique_ptr<GameDashboardContext>> |
| game_window_contexts_; |
| |
| // The delegate responsible for communicating with between Ash and the Game |
| // Dashboard service in the browser. |
| std::unique_ptr<GameDashboardDelegate> delegate_; |
| |
| base::ScopedObservation<aura::Env, aura::EnvObserver> env_observation_{this}; |
| |
| base::ScopedMultiSourceObservation<aura::Window, aura::WindowObserver> |
| window_observations_{this}; |
| |
| display::ScopedDisplayObserver display_observer_{this}; |
| |
| // Represents the active `GameDashboardContext`. If |
| // `active_recording_context_` is non-null, then `CaptureModeController` is |
| // recording the game window, or has been requested to record it. Resets |
| // when the recording session ends or aborted. |
| // Owned by `game_window_contexts_`. |
| raw_ptr<GameDashboardContext, DanglingUntriaged> active_recording_context_ = |
| nullptr; |
| |
| base::WeakPtrFactory<GameDashboardController> weak_ptr_factory_{this}; |
| }; |
| |
| } // namespace ash |
| |
| #endif // ASH_GAME_DASHBOARD_GAME_DASHBOARD_CONTROLLER_H_ |