chromium/chrome/browser/ui/ash/session/session_controller_client_impl.h

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_UI_ASH_SESSION_SESSION_CONTROLLER_CLIENT_IMPL_H_
#define CHROME_BROWSER_UI_ASH_SESSION_SESSION_CONTROLLER_CLIENT_IMPL_H_

#include <memory>
#include <set>
#include <vector>

#include "ash/public/cpp/session/session_controller_client.h"
#include "base/callback_list.h"
#include "base/functional/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/ash/crosapi/browser_manager_observer.h"
#include "chrome/browser/ash/policy/off_hours/device_off_hours_controller.h"
#include "chromeos/ash/components/login/login_state/login_state.h"
#include "components/session_manager/core/session_manager_observer.h"
#include "components/supervised_user/core/browser/supervised_user_service_observer.h"
#include "components/user_manager/user_manager.h"

class Profile;
class PrefChangeRegistrar;

namespace ash {
enum class AddUserSessionPolicy;
}

namespace user_manager {
class User;
}

// Updates session state etc to ash via SessionController interface and handles
// session related calls from ash.
// TODO(xiyuan): Update when UserSessionStateObserver is gone.
class SessionControllerClientImpl
    : public ash::SessionControllerClient,
      public user_manager::UserManager::UserSessionStateObserver,
      public user_manager::UserManager::Observer,
      public session_manager::SessionManagerObserver,
      public SupervisedUserServiceObserver,
      public policy::off_hours::DeviceOffHoursController::Observer,
      public crosapi::BrowserManagerObserver {
 public:
  SessionControllerClientImpl();

  SessionControllerClientImpl(const SessionControllerClientImpl&) = delete;
  SessionControllerClientImpl& operator=(const SessionControllerClientImpl&) =
      delete;

  ~SessionControllerClientImpl() override;

  void Init();

  static SessionControllerClientImpl* Get();

  // Calls SessionController to prepare locking ash.
  void PrepareForLock(base::OnceClosure callback);

  // Calls SessionController to start locking ash. |callback| will be invoked
  // to indicate whether the lock is successful. If |locked| is true, the post
  // lock animation is finished and ash is fully locked. Otherwise, the lock
  // is failed somehow.
  using StartLockCallback = base::OnceCallback<void(bool locked)>;
  void StartLock(StartLockCallback callback);

  // Notifies SessionController that chrome lock animations are finished.
  void NotifyChromeLockAnimationsComplete();

  // Calls ash SessionController to run unlock animation.
  // |animation_finished_callback| will be invoked when the animation finishes.
  void RunUnlockAnimation(ash::SessionController::RunUnlockAnimationCallback
                              animation_finished_callback);

  // Asks the session controller to show the window teleportation dialog.
  void ShowTeleportWarningDialog(
      base::OnceCallback<void(bool, bool)> on_accept);

  // ash::SessionControllerClient:
  void RequestLockScreen() override;
  void RequestHideLockScreen() override;
  void RequestSignOut() override;
  void RequestRestartForUpdate() override;
  void AttemptRestartChrome() override;
  void SwitchActiveUser(const AccountId& account_id) override;
  void CycleActiveUser(ash::CycleUserDirection direction) override;
  void ShowMultiProfileLogin() override;
  void EmitAshInitialized() override;
  PrefService* GetSigninScreenPrefService() override;
  PrefService* GetUserPrefService(const AccountId& account_id) override;
  base::FilePath GetProfilePath(const AccountId& account_id) override;
  std::tuple<bool, bool> IsEligibleForSeaPen(
      const AccountId& account_id) override;
  std::optional<int> GetExistingUsersCount() const override;

  // Returns true if a multi-profile user can be added to the session or if
  // multiple users are already signed in.
  static bool IsMultiProfileAvailable();

  // user_manager::UserManager::UserSessionStateObserver:
  void ActiveUserChanged(user_manager::User* active_user) override;
  void UserAddedToSession(const user_manager::User* added_user) override;

  // user_manager::UserManager::Observer
  void LocalStateChanged(user_manager::UserManager* user_manager) override;
  void OnUserImageChanged(const user_manager::User& user) override;
  void OnUserNotAllowed(const std::string& user_email) override;

  // session_manager::SessionManagerObserver:
  void OnSessionStateChanged() override;
  void OnUserProfileLoaded(const AccountId& account_id) override;
  void OnUserSessionStartUpTaskCompleted() override;

  // SupervisedUserServiceObserver:
  void OnCustodianInfoChanged() override;

  // DeviceOffHoursController::Observer:
  void OnOffHoursEndTimeChanged() override;

  // TODO(xiyuan): Remove after SessionStateDelegateChromeOS is gone.
  static bool CanLockScreen();
  static bool ShouldLockScreenAutomatically();
  static ash::AddUserSessionPolicy GetAddUserSessionPolicy();
  static void DoLockScreen();
  static void DoSwitchActiveUser(const AccountId& account_id);
  static void DoCycleActiveUser(ash::CycleUserDirection direction);

 private:
  FRIEND_TEST_ALL_PREFIXES(SessionControllerClientImplTest, CyclingThreeUsers);
  FRIEND_TEST_ALL_PREFIXES(SessionControllerClientImplTest, SendUserSession);
  FRIEND_TEST_ALL_PREFIXES(SessionControllerClientImplTest, SupervisedUser);
  FRIEND_TEST_ALL_PREFIXES(SessionControllerClientImplTest, UserPrefsChange);
  FRIEND_TEST_ALL_PREFIXES(SessionControllerClientImplTest, SessionLengthLimit);
  FRIEND_TEST_ALL_PREFIXES(SessionControllerClientImplTest, DeviceOwner);
  FRIEND_TEST_ALL_PREFIXES(SessionControllerClientImplTest,
                           UserBecomesDeviceOwner);

  // Called when the login profile is ready.
  void OnLoginUserProfilePrepared(Profile* profile);

  // Sends session info to ash.
  void SendSessionInfoIfChanged();

  // Sends the user session info.
  void SendUserSession(const user_manager::User& user);

  // Sends the order of user sessions to ash.
  void SendUserSessionOrder();

  // Sends the session length time limit to ash considering two policies which
  // restrict session length: "SessionLengthLimit" and "OffHours". Send limit
  // from "SessionLengthLimit" policy if "OffHours" mode is off now or if
  // "SessionLengthLimit" policy will be ended earlier than "OffHours" mode.
  // Send limit from "OffHours" policy if "SessionLengthLimit" policy is unset
  // or if "OffHours" mode will be ended earlier than "SessionLengthLimit"
  // policy.
  void SendSessionLengthLimit();

  // Called when application is terminating
  void OnAppTerminating();

  // crosapi::BrowserManagerObserver:
  void OnStateChanged() override;

  // SessionController instance in ash.
  raw_ptr<ash::SessionController> session_controller_ = nullptr;

  // Tracks users whose profiles are being loaded.
  std::set<AccountId> pending_users_;

  // If the session is for a supervised user, the profile of that user.
  // Chrome OS only supports a single supervised user in a session.
  raw_ptr<Profile> supervised_user_profile_ = nullptr;

  base::CallbackListSubscription subscription_;

  // Pref change observers to update session info when a relevant user pref
  // changes. There is one observer per user and they have no particular order,
  // i.e. they don't much the user session order.
  std::vector<std::unique_ptr<PrefChangeRegistrar>> pref_change_registrars_;

  // Observes changes to Local State prefs.
  std::unique_ptr<PrefChangeRegistrar> local_state_registrar_;

  // Used to suppress duplicate calls to ash.
  std::unique_ptr<ash::SessionInfo> last_sent_session_info_;
  std::unique_ptr<ash::UserSession> last_sent_user_session_;

  base::WeakPtrFactory<SessionControllerClientImpl> weak_ptr_factory_{this};
};

#endif  // CHROME_BROWSER_UI_ASH_SESSION_SESSION_CONTROLLER_CLIENT_IMPL_H_