// 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_USER_EDUCATION_WELCOME_TOUR_WELCOME_TOUR_CONTROLLER_H_
#define ASH_USER_EDUCATION_WELCOME_TOUR_WELCOME_TOUR_CONTROLLER_H_
#include <memory>
#include "ash/accessibility/accessibility_observer.h"
#include "ash/ash_export.h"
#include "ash/public/cpp/session/session_observer.h"
#include "ash/shell_observer.h"
#include "ash/user_education/user_education_feature_controller.h"
#include "ash/user_education/welcome_tour/welcome_tour_metrics.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/scoped_observation.h"
#include "base/timer/elapsed_timer.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/display/display_observer.h"
namespace display {
class Screen;
enum class TabletState;
} // namespace display
namespace user_education {
struct TutorialDescription;
} // namespace user_education
namespace ash {
class AccessibilityController;
class ScopedNudgePause;
class ScopedToastPause;
class SessionController;
class Shell;
class WelcomeTourAcceleratorHandler;
class WelcomeTourControllerObserver;
class WelcomeTourNotificationBlocker;
class WelcomeTourScrim;
class WelcomeTourWindowMinimizer;
// Controller responsible for the Welcome Tour feature tutorial. Note that the
// `WelcomeTourController` is owned by the `UserEducationController` and exists
// if and only if the Welcome Tour feature is enabled.
class ASH_EXPORT WelcomeTourController : public UserEducationFeatureController,
public AccessibilityObserver,
public SessionObserver,
public ShellObserver,
public display::DisplayObserver {
public:
WelcomeTourController();
WelcomeTourController(const WelcomeTourController&) = delete;
WelcomeTourController& operator=(const WelcomeTourController&) = delete;
~WelcomeTourController() override;
// Returns the singleton instance owned by the `UserEducationController`.
// NOTE: Exists if and only if the Welcome Tour feature is enabled.
static WelcomeTourController* Get();
// Adds/removes the specified `observer` from being notified of events.
void AddObserver(WelcomeTourControllerObserver* observer);
void RemoveObserver(WelcomeTourControllerObserver* observer);
// Returns the initial element context to be used to start the Welcome Tour.
ui::ElementContext GetInitialElementContext() const;
// Returns the tutorial description for the Welcome Tour.
user_education::TutorialDescription GetTutorialDescription() const;
private:
// AccessibilityObserver:
void OnAccessibilityControllerShutdown() override;
void OnAccessibilityStatusChanged() override;
// SessionObserver:
void OnActiveUserPrefServiceChanged(PrefService* pref_service) override;
void OnActiveUserSessionChanged(const AccountId& account_id) override;
void OnChromeTerminating() override;
void OnSessionStateChanged(session_manager::SessionState) override;
// ShellObserver:
void OnShellDestroying() override;
// display::DisplayObserver:
void OnDisplayTabletStateChanged(display::TabletState state) override;
// Starts the Welcome Tour if and only if the primary user session is active.
void MaybeStartWelcomeTour();
// Aborts the Welcome Tour if and only if the tour is in progress.
void MaybeAbortWelcomeTour(welcome_tour_metrics::AbortedReason reason);
// Invoked when the Welcome Tour is started/ended. The latter is called
// regardless of whether the tour was `completed` or aborted.
void OnWelcomeTourStarted();
void OnWelcomeTourEnded(bool completed, base::ElapsedTimer time_since_start);
// Sets the current step of the tutorial, since that information is not
// directly available.
void SetCurrentStep(std::optional<welcome_tour_metrics::Step> step);
// The reason the tour was aborted.
welcome_tour_metrics::AbortedReason aborted_reason_ =
welcome_tour_metrics::AbortedReason::kUnknown;
// The current step of the Welcome Tour, if it is active. Tracked here because
// it is not directly available from the tutorial.
std::optional<welcome_tour_metrics::Step> current_step_;
// The elapsed time since the beginning of the `current_step_`.
base::ElapsedTimer current_step_timer_;
// Handles accelerator actions during the Welcome Tour. Exists only while the
// Welcome Tour is in progress.
std::unique_ptr<WelcomeTourAcceleratorHandler> accelerator_handler_;
// Blocks all notifications while the Welcome Tour is in progress. Any
// notifications received during the tour will appear in the Notification
// Center after the tour is over.
std::unique_ptr<WelcomeTourNotificationBlocker> notification_blocker_;
// Suppresses all nudges during the Welcome Tour. Exists only while the
// Welcome Tour is in progress.
std::unique_ptr<ScopedNudgePause> nudge_pause_;
// Used to apply a scrim to the help bubble container on all root windows
// while the Welcome Tour is in progress. Exists only while the Welcome Tour
// is in progress.
std::unique_ptr<WelcomeTourScrim> scrim_;
// Suppresses all toasts during the Welcome Tour. Exists only while the
// Welcome Tour is in progress.
std::unique_ptr<ScopedToastPause> toast_pause_;
// Minimizes any app windows that are visible at the start of the Welcome
// Tour, and any that attempt to become visible during the tour. Exists only
// while the Welcome Tour is in progress.
std::unique_ptr<WelcomeTourWindowMinimizer> window_minimizer_;
// The collection of observers to be notified of events.
base::ObserverList<WelcomeTourControllerObserver> observer_list_;
// The accessibility controller is observed only while the Welcome Tour is in
// progress, and will trigger an abort of the tour if ChromeVox is enabled.
base::ScopedObservation<AccessibilityController, AccessibilityObserver>
accessibility_observation_{this};
// Sessions are observed only until the primary user session is activated for
// the first time at which point the Welcome Tour is started.
base::ScopedObservation<SessionController, SessionObserver>
session_observation_{this};
// Shell is observed only while the Welcome Tour is in progress. The Welcome
// Tour is aborted when Shell is destroying to ensure the Welcome Tour does
// not outlive its dependencies.
base::ScopedObservation<Shell, ShellObserver> shell_observation_{this};
// Display is observed only while the Welcome Tour is in progress, and will
// trigger an abort of the tour if the device switches to tablet mode.
base::ScopedObservation<display::Screen, display::DisplayObserver>
display_observation_{this};
// It is theoretically possible for the Welcome Tour tutorial to outlive
// `this` controller during the destruction sequence.
base::WeakPtrFactory<WelcomeTourController> weak_ptr_factory_{this};
};
} // namespace ash
#endif // ASH_USER_EDUCATION_WELCOME_TOUR_WELCOME_TOUR_CONTROLLER_H_