blob: fa39613ba27eca91c2b0254cffaff170d6541949 [file] [log] [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 CHROME_BROWSER_ASH_LOGIN_QUICKSTART_CONTROLLER_H_
#define CHROME_BROWSER_ASH_LOGIN_QUICKSTART_CONTROLLER_H_
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "base/scoped_observation.h"
#include "chrome/browser/ash/login/oobe_quick_start/connectivity/fido_assertion_info.h"
#include "chrome/browser/ash/login/oobe_quick_start/connectivity/target_device_connection_broker.h"
#include "chrome/browser/ash/login/oobe_quick_start/target_device_bootstrap_controller.h"
#include "chrome/browser/ash/login/oobe_screen.h"
#include "chrome/browser/ui/webui/ash/login/oobe_ui.h"
#include "chromeos/ash/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom-forward.h"
#include "chromeos/ash/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom-shared.h"
#include "chromeos/ash/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace ash::quick_start {
class QuickStartMetrics;
// Main orchestrator of the QuickStart flow in OOBE
//
// QuickStartController holds all the logic for QuickStart and acts as the
// source of truth for what the UI (QuickStartScreen) should be showing. Unlike
// other OOBE screens, QuickStartScreen just acts as a delegate for this main
// controller.
class QuickStartController
: public OobeUI::Observer,
public TargetDeviceBootstrapController::Observer,
public bluetooth_config::mojom::SystemPropertiesObserver {
public:
using AbortFlowReason = QuickStartMetrics::AbortFlowReason;
using EntryPoint = QuickStartMetrics::EntryPoint;
// Main state used by the controller.
// TODO(b:283965994) - Finalize states.
enum class ControllerState {
NOT_ACTIVE,
WAITING_FOR_BLUETOOTH_PERMISSION,
WAITING_FOR_BLUETOOTH_ACTIVATION,
WAITING_TO_RESUME_AFTER_UPDATE,
INITIALIZING,
ADVERTISING,
CONNECTED,
// TODO(b:283965994) - Replace with more appropriate state.
CONTINUING_AFTER_ENROLLMENT_CHECKS,
FALLBACK_URL_FLOW_ON_GAIA_SCREEN,
SETUP_COMPLETE,
};
// Implemented by the QuickStartScreen
class UiDelegate : public base::CheckedObserver {
public:
// UI State that is used for dictating what the QuickStartScreen should
// show.
enum class UiState {
SHOWING_BLUETOOTH_DIALOG,
CONNECTING_TO_PHONE,
SHOWING_QR,
SHOWING_PIN,
CONNECTING_TO_WIFI,
WIFI_CREDENTIALS_RECEIVED,
CONFIRM_GOOGLE_ACCOUNT,
SIGNING_IN,
// Same state as 'SIGNING_IN' but without the 'Cancel' button.
CREATING_ACCOUNT,
// Triggers a screen exit into the Gaia screen for the fallback URL flow.
FALLBACK_URL_FLOW,
SETUP_COMPLETE,
// Exits the screen.
EXIT_SCREEN,
};
virtual void OnUiUpdateRequested(UiState desired_state) = 0;
protected:
~UiDelegate() override = default;
};
// For showing the user information on the UI
struct UserInfo {
std::string email = "";
std::string full_name = "";
std::string avatar_url = "";
};
// EntryPointButtonVisibilityCallback is a RepeatingCallback since the
// bluetooth adapter may not be present and powered the first time it's
// invoked. The bluetooth adapter asynchronously affects the feature support
// status and thus the entry point visibility.
using EntryPointButtonVisibilityCallback =
base::RepeatingCallback<void(bool)>;
using UiState = UiDelegate::UiState;
QuickStartController();
QuickStartController(const QuickStartController&) = delete;
QuickStartController& operator=(const QuickStartController&) = delete;
~QuickStartController() override;
// Enable QuickStart even when the feature isn't enabled. This is only called
// when enabling via the keyboard shortcut Ctrl+Alt+Q on the Welcome screen.
void ForceEnableQuickStart();
// Whether QuickStart is supported. Used for determining whether the entry
// point buttons are shown.
void DetermineEntryPointVisibility(
EntryPointButtonVisibilityCallback callback);
// Invoked by the frontend whenever the user cancels the flow or proceeds with
// enterprise enrollment, the flow completes, or we encounter an error.
void AbortFlow(AbortFlowReason reason);
// Whether QuickStart is ongoing and orchestrating the flow.
bool IsSetupOngoing() {
return controller_state_ != ControllerState::NOT_ACTIVE;
}
// Whenever the QuickStartScreen is shown, it will attach itself and observe
// the controller so that it knows when to update the UI.
void AttachFrontend(UiDelegate* delegate);
void DetachFrontend(UiDelegate* delegate);
// Accessors methods to be used by the UI for retrieving data. It is an error
// to retrieve these values when they do not exist.
QRCode GetQrCode() { return qr_code_.value(); }
std::string GetPin() { return pin_.value(); }
UserInfo GetUserInfo() { return user_info_; }
std::string GetWiFiName() { return wifi_name_.value(); }
std::string GetFallbackUrl() { return fallback_url_.value(); }
// If we're already connected to Wi-Fi at the start of the flow we won't
// request Wi-Fi details from the source device. This lets us reflect that in
// the UI.
bool WillRequestWiFi();
// Called by the Gaia screen during the 'CompleteAuthentication' call. This
// notifies us that the flow succeeded and we use this signal to show the
// 'setup complete' step of QuickStart.
void OnFallbackUrlFlowSuccess();
// Triggered when the user clicks on 'Turn on Bluetooth'
void OnBluetoothPermissionGranted();
// Exit point to be used when the flow is cancelled.
EntryPoint GetExitPoint();
// Exposes TargetDeviceBootstrapController::PrepareForUpdate() to the OOBE
// UpdateScreen and ConsumerUpdateScreen.
void PrepareForUpdate(bool is_forced);
// Resumes current session if an update is aborted on
// the OOBE UpdateScreen or ConsumerUpdateScreen.
void ResumeSessionAfterCancelledUpdate();
// Called after a user clicks "next" on final Setup Complete UI.
void RecordFlowFinished();
bool did_transfer_wifi() const {
return bootstrap_controller_->did_transfer_wifi();
}
private:
// Initializes the BootstrapController and starts to observe it.
void InitTargetDeviceBootstrapController();
// Initializes the Bluetooth and starts to observe it.
void StartObservingBluetoothState();
// Request advertising to start. Should only be called when bluetooth is
// enabled.
void StartAdvertising();
// bluetooth_config::mojom::SystemPropertiesObserver
void OnPropertiesUpdated(bluetooth_config::mojom::BluetoothSystemPropertiesPtr
properties) override;
// Records ScreenOpened metric when UiState or OOBE screen changes.
void MaybeRecordQuickStartScreenOpened(UiState new_ui);
// Records ScreenClosed metric when UiState or OOBE screen changes.
void MaybeRecordQuickStartScreenAdvanced(std::optional<UiState> closed_ui);
// Updates the UI state and notifies the frontend.
void UpdateUiState(UiState ui_state);
// TargetDeviceBootstrapController::Observer
void OnStatusChanged(
const TargetDeviceBootstrapController::Status& status) final;
void OnGetQuickStartFeatureSupportStatus(
EntryPointButtonVisibilityCallback callback,
TargetDeviceConnectionBroker::FeatureSupportStatus status);
// OobeUI::Observer:
void OnCurrentScreenChanged(OobeScreenId previous_screen,
OobeScreenId current_screen) override;
void OnDestroyingOobeUI() override;
// Activates the OobeUI::Observer
void StartObservingScreenTransitions();
// Invoked whenever OOBE transitions into the QuickStart screen.
void HandleTransitionToQuickStartScreen();
// Starts transferring the user account from the phone.
void StartAccountTransfer();
// Steps to take when all the account data has been exchanged with the phone.
void OnOAuthTokenReceived(TargetDeviceBootstrapController::GaiaCredentials);
// Steps to take when the connection with the phone is fully established.
// Either transfers WiFi credentials if early in the OOBE flow, or starts
// to transfer the user's credentials.
void OnPhoneConnectionEstablished();
void SavePhoneInstanceID();
// Performs the final steps and triggers ChromeOS account creation flow.
void FinishAccountCreation();
bool IsBluetoothDisabled();
// Resets all internal values. Invoked when the flow is interrupted.
void ResetState();
// "Main" controller for interacting with the phone. Only valid when the
// feature flag is enabled or if the feature was enabled via the keyboard
// shortcut.
base::WeakPtr<TargetDeviceBootstrapController> bootstrap_controller_;
// Source of truth of OOBE's current state via OobeUI::Observer
std::optional<OobeScreenId> current_screen_, previous_screen_;
// Bookkeeping where the quick start flow started and ended.
std::optional<EntryPoint> entry_point_, exit_point_;
// QR Code to be shown on the UI when requested.
std::optional<QRCode> qr_code_;
// PIN to be shown on the UI when requested.
std::optional<std::string> pin_;
// Fallback URL to be used on the Gaia screen when needed.
std::optional<std::string> fallback_url_;
// User information that is shown while 'Signing in...'
UserInfo user_info_;
// WiFi name to be shown on the UI.
std::optional<std::string> wifi_name_;
// Main state that the controller can be in.
ControllerState controller_state_ = ControllerState::NOT_ACTIVE;
// UI state that should be displayed by the QuickStartScreen. Only exists when
// there is an ongoing setup.
std::optional<UiState> ui_state_;
// QuickStartScreen implements the UiDelegate and registers itself whenever it
// is shown. UI updates happen over this observation path.
base::ObserverList<UiDelegate> ui_delegates_;
std::unique_ptr<QuickStartMetrics> metrics_;
// Gaia credentials used for account creation.
TargetDeviceBootstrapController::GaiaCredentials gaia_creds_;
mojo::Remote<bluetooth_config::mojom::CrosBluetoothConfig>
cros_bluetooth_config_remote_;
mojo::Receiver<bluetooth_config::mojom::SystemPropertiesObserver>
cros_system_properties_observer_receiver_{this};
bluetooth_config::mojom::BluetoothSystemState bluetooth_system_state_ =
bluetooth_config::mojom::BluetoothSystemState::kUnavailable;
// Whether OOBE is transitioning to the QuickStartScreen. Used for recording
// UI metrics.
bool is_transitioning_to_quick_start_screen_ = false;
bool should_resume_quick_start_after_update_ = false;
// Used for sanity checks in order to discard unrequested data from the phone.
// Similar checks exist on the TargetDeviceBootstrapController level.
bool did_request_wifi_credentials_ = false;
bool did_request_account_info_ = false;
bool did_request_account_transfer_ = false;
base::ScopedObservation<OobeUI, OobeUI::Observer> observation_{this};
base::WeakPtrFactory<QuickStartController> weak_ptr_factory_{this};
};
std::ostream& operator<<(std::ostream& stream,
const QuickStartController::UiState& ui_state);
std::ostream& operator<<(
std::ostream& stream,
const QuickStartController::AbortFlowReason& abort_flow_reason);
std::ostream& operator<<(
std::ostream& stream,
const QuickStartController::ControllerState& controller_state);
} // namespace ash::quick_start
#endif // CHROME_BROWSER_ASH_LOGIN_QUICKSTART_CONTROLLER_H_