chromium/chromeos/ash/components/network/hotspot_controller.h

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

#ifndef CHROMEOS_ASH_COMPONENTS_NETWORK_HOTSPOT_CONTROLLER_H_
#define CHROMEOS_ASH_COMPONENTS_NETWORK_HOTSPOT_CONTROLLER_H_

#include <memory>

#include "base/component_export.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/elapsed_timer.h"
#include "chromeos/ash/components/network/hotspot_capabilities_provider.h"
#include "chromeos/ash/components/network/hotspot_state_handler.h"
#include "chromeos/ash/components/network/technology_state_controller.h"
#include "chromeos/ash/services/hotspot_config/public/mojom/cros_hotspot_config.mojom-forward.h"

namespace ash {

class HotspotFeatureUsageMetrics;

// Handles enable or disable hotspot.
//
// Enabling the hotspot involves the following operations:
// 1. Check hotspot capabilities
// 2. Check tethering readiness
// 3. Enable tethering from Shill
//
// Enable or disable requests executed as they come in but are ignored if there
// is already a pending request.
class COMPONENT_EXPORT(CHROMEOS_NETWORK) HotspotController
    : public TechnologyStateController::HotspotOperationDelegate,
      public HotspotStateHandler::Observer {
 public:
  class Observer : public base::CheckedObserver {
   public:
    ~Observer() override = default;

    virtual void OnHotspotTurnedOn() = 0;

    virtual void OnHotspotTurnedOff(
        hotspot_config::mojom::DisableReason disable_reason) = 0;
  };
  HotspotController();
  HotspotController(const HotspotController&) = delete;
  HotspotController& operator=(const HotspotController&) = delete;
  ~HotspotController() override;

  void Init(HotspotCapabilitiesProvider* hotspot_capabilities_provider,
            HotspotFeatureUsageMetrics* hotspot_feature_usage_metrics,
            HotspotStateHandler* hotspot_state_handler,
            TechnologyStateController* technolog_state_controller);

  // Return callback for the EnableHotspot or DisableHotspot method.
  using HotspotControlCallback = base::OnceCallback<void(
      hotspot_config::mojom::HotspotControlResult control_result)>;

  // Checks if there is an existing request and if there isn't one, proceeds to
  // execute it.
  void EnableHotspot(HotspotControlCallback callback);
  void DisableHotspot(HotspotControlCallback callback,
                      hotspot_config::mojom::DisableReason disable_reason);

  // Set whether Hotspot should be allowed/disallowed by policy.
  void SetPolicyAllowHotspot(bool allow_hotspot);

  void AddObserver(Observer* observer);
  void RemoveObserver(Observer* observer);
  bool HasObserver(Observer* observer) const;

 private:
  friend class HotspotControllerTest;
  friend class HotspotControllerConcurrencyApiTest;
  friend class HotspotEnabledStateNotifierTest;

  // Represents hotspot enable or disable control request parameters. Requests
  // are executed as they come in.
  struct HotspotControlRequest {
    HotspotControlRequest(
        bool enabled,
        std::optional<hotspot_config::mojom::DisableReason> disable_reason,
        HotspotControlCallback callback);
    HotspotControlRequest(const HotspotControlRequest&) = delete;
    HotspotControlRequest& operator=(const HotspotControlRequest&) = delete;
    ~HotspotControlRequest();

    bool enabled;
    bool abort = false;
    // Set for disable requests and will be nullopt for enable requests.
    std::optional<hotspot_config::mojom::DisableReason> disable_reason;
    // Tracks the latency of enable hotspot operation and will be nullopt for
    // disable requests.
    std::optional<base::ElapsedTimer> enable_latency_timer;
    HotspotControlCallback callback;
  };

  // TechnologyStateController::HotspotOperationDelegate:
  void PrepareEnableWifi(
      base::OnceCallback<void(bool prepare_success)> callback) override;

  // HotspotStateHandler::Observer:
  void OnHotspotStatusChanged() override;

  void OnCheckTetheringReadiness(
      HotspotCapabilitiesProvider::CheckTetheringReadinessResult result);
  void PerformSetTetheringEnabled(bool enabled);
  void OnSetTetheringEnabledSuccess(const bool& enabled,
                                    const std::string& result);
  void OnSetTetheringEnabledFailure(const bool& enabled,
                                    const std::string& error_name,
                                    const std::string& error_message);
  void OnPrepareEnableHotspotCompleted(bool prepare_success,
                                       bool wifi_turned_off);
  void OnPrepareEnableWifiCompleted(
      base::OnceCallback<void(bool success)> callback,
      hotspot_config::mojom::HotspotControlResult control_result);
  void CompleteCurrentRequest(
      const bool& enabled,
      hotspot_config::mojom::HotspotControlResult result);
  void CompleteEnableRequest(
      hotspot_config::mojom::HotspotControlResult result);
  void CompleteDisableRequest(
      hotspot_config::mojom::HotspotControlResult result);
  void NotifyHotspotTurnedOn();
  void NotifyHotspotTurnedOff(
      hotspot_config::mojom::DisableReason disable_reason);

  std::unique_ptr<HotspotControlRequest> current_enable_request_;
  std::unique_ptr<HotspotControlRequest> current_disable_request_;

  bool allow_hotspot_ = true;
  // Store whether the WiFi was turned off due to the start of hotspot. Need to
  // restore the WiFi status once hotspot is turned off.
  bool wifi_turned_off_ = false;

  raw_ptr<HotspotCapabilitiesProvider> hotspot_capabilities_provider_ = nullptr;
  raw_ptr<HotspotFeatureUsageMetrics> hotspot_feature_usage_metrics_ = nullptr;
  raw_ptr<HotspotStateHandler> hotspot_state_handler_ = nullptr;
  raw_ptr<TechnologyStateController> technology_state_controller_ = nullptr;

  base::ObserverList<Observer> observer_list_;
  base::WeakPtrFactory<HotspotController> weak_ptr_factory_{this};
};

}  // namespace ash

#endif  // CHROMEOS_ASH_COMPONENTS_NETWORK_HOTSPOT_CONTROLLER_H_