text: // Copyright (c) 2013 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef DEVICE_BLUETOOTH_DBUS_FAKE_BLUETOOTH_DEVICE_CLIENT_H_
  #define DEVICE_BLUETOOTH_DBUS_FAKE_BLUETOOTH_DEVICE_CLIENT_H_
  
  #include <cstdint>
  #include <map>
  #include <memory>
  #include <vector>
  
  #include "base/bind.h"
  #include "base/callback.h"
  #include "base/observer_list.h"
  #include "base/optional.h"
  #include "dbus/object_path.h"
  #include "dbus/property.h"
  #include "device/bluetooth/bluetooth_common.h"
  #include "device/bluetooth/bluetooth_export.h"
  #include "device/bluetooth/dbus/bluetooth_agent_service_provider.h"
  #include "device/bluetooth/dbus/bluetooth_device_client.h"
  #include "device/bluetooth/dbus/bluetooth_profile_service_provider.h"
  
  namespace bluez {
  
  // FakeBluetoothDeviceClient simulates the behavior of the Bluetooth Daemon
  // device objects and is used both in test cases in place of a mock and on
  // the Linux desktop.
  class DEVICE_BLUETOOTH_EXPORT FakeBluetoothDeviceClient
      : public BluetoothDeviceClient {
   public:
    struct Properties : public BluetoothDeviceClient::Properties {
      explicit Properties(const PropertyChangedCallback& callback);
      ~Properties() override;
  
      // dbus::PropertySet override
      void Get(dbus::PropertyBase* property,
               dbus::PropertySet::GetCallback callback) override;
      void GetAll() override;
      void Set(dbus::PropertyBase* property,
               dbus::PropertySet::SetCallback callback) override;
    };
  
    struct SimulatedPairingOptions {
      SimulatedPairingOptions();
      ~SimulatedPairingOptions();
  
      bool incoming = false;
      std::string pairing_method;
      std::string pairing_auth_token;
      std::string pairing_action;
    };
  
    // Stores properties of a device that is about to be created.
    struct IncomingDeviceProperties {
      IncomingDeviceProperties();
      ~IncomingDeviceProperties();
  
      std::string device_address;
      std::string device_alias;
      int device_class = 0;
      std::string device_name;
      std::string device_path;
      bool is_trusted = true;
      bool incoming = false;
      std::string pairing_action;
      std::string pairing_auth_token;
      std::string pairing_method;
    };
  
    FakeBluetoothDeviceClient();
    ~FakeBluetoothDeviceClient() override;
  
    // Causes Connect() calls to never finish.
    void LeaveConnectionsPending();
  
    // BluetoothDeviceClient overrides
    void Init(dbus::Bus* bus, const std::string& bluetooth_service_name) override;
    void AddObserver(Observer* observer) override;
    void RemoveObserver(Observer* observer) override;
    std::vector<dbus::ObjectPath> GetDevicesForAdapter(
        const dbus::ObjectPath& adapter_path) override;
    Properties* GetProperties(const dbus::ObjectPath& object_path) override;
    void Connect(const dbus::ObjectPath& object_path,
                 base::OnceClosure callback,
                 ErrorCallback error_callback) override;
    void Disconnect(const dbus::ObjectPath& object_path,
                    base::OnceClosure callback,
                    ErrorCallback error_callback) override;
    void ConnectProfile(const dbus::ObjectPath& object_path,
                        const std::string& uuid,
                        base::OnceClosure callback,
                        ErrorCallback error_callback) override;
    void DisconnectProfile(const dbus::ObjectPath& object_path,
                           const std::string& uuid,
                           base::OnceClosure callback,
                           ErrorCallback error_callback) override;
    void Pair(const dbus::ObjectPath& object_path,
              base::OnceClosure callback,
              ErrorCallback error_callback) override;
    void CancelPairing(const dbus::ObjectPath& object_path,
                       base::OnceClosure callback,
                       ErrorCallback error_callback) override;
    void GetConnInfo(const dbus::ObjectPath& object_path,
                     ConnInfoCallback callback,
                     ErrorCallback error_callback) override;
    void SetLEConnectionParameters(const dbus::ObjectPath& object_path,
                                   const ConnectionParameters& conn_params,
                                   base::OnceClosure callback,
                                   ErrorCallback error_callback) override;
    void GetServiceRecords(const dbus::ObjectPath& object_path,
                           ServiceRecordsCallback callback,
                           ErrorCallback error_callback) override;
    void ExecuteWrite(const dbus::ObjectPath& object_path,
                      base::OnceClosure callback,
                      ErrorCallback error_callback) override;
    void AbortWrite(const dbus::ObjectPath& object_path,
                    base::OnceClosure callback,
                    ErrorCallback error_callback) override;
  
    void SetSimulationIntervalMs(int interval_ms);
  
    // Simulates discovery of devices for the given adapter.
    void BeginDiscoverySimulation(const dbus::ObjectPath& adapter_path);
    void EndDiscoverySimulation(const dbus::ObjectPath& adapter_path);
  
    // Simulates incoming pairing of devices for the given adapter.
    void BeginIncomingPairingSimulation(const dbus::ObjectPath& adapter_path);
    void EndIncomingPairingSimulation(const dbus::ObjectPath& adapter_path);
  
    // Creates a device from the set we return for the given adapter.
    void CreateDevice(const dbus::ObjectPath& adapter_path,
                      const dbus::ObjectPath& device_path);
  
    // Creates a device with the given properties.
    void CreateDeviceWithProperties(const dbus::ObjectPath& adapter_path,
                                    const IncomingDeviceProperties& props);
  
    // Creates and returns a list of std::unique_ptr<base::DictionaryValue>
    // objects, which contain all the data from the constants for devices with
    // predefined behavior.
    std::unique_ptr<base::ListValue> GetBluetoothDevicesAsDictionaries() const;
  
    SimulatedPairingOptions* GetPairingOptions(
        const dbus::ObjectPath& object_path);
  
    // Removes a device from the set we return for the given adapter.
    void RemoveDevice(const dbus::ObjectPath& adapter_path,
                      const dbus::ObjectPath& device_path);
  
    // Simulates a pairing for the device with the given D-Bus object path,
    // |object_path|. Set |incoming_request| to true if simulating an incoming
    // pairing request, false for an outgoing one. On successful completion
    // |callback| will be called, on failure, |error_callback| is called.
    void SimulatePairing(const dbus::ObjectPath& object_path,
                         bool incoming_request,
                         base::OnceClosure callback,
                         ErrorCallback error_callback);
  
    // Updates the connection properties of the fake device that will be returned
    // by GetConnInfo.
    void UpdateConnectionInfo(uint16_t connection_rssi,
                              uint16_t transmit_power,
                              uint16_t max_transmit_power);
  
    // Test specific functions:
    // Remove all test devices from this client.
    void RemoveAllDevices();
  
    // Create a test Bluetooth device with the given properties.
    void CreateTestDevice(
        const dbus::ObjectPath& adapter_path,
        const base::Optional<std::string> name,
        const std::string alias,
        const std::string device_address,
        const std::vector<std::string>& service_uuids,
        device::BluetoothTransport type,
        const std::map<std::string, std::vector<uint8_t>>& service_data,
        const std::map<uint16_t, std::vector<uint8_t>>& manufacturer_data);
  
    void set_delay_start_discovery(bool value) { delay_start_discovery_ = value; }
  
    // Updates the inquiry RSSI property of fake device with object path
    // |object_path| to |rssi|, if the fake device exists.
    void UpdateDeviceRSSI(const dbus::ObjectPath& object_path, int16_t rssi);
  
    // Updates service UUIDs, service data, and manufacturer data of the fake
    // device with the given |object_path|. The |service_uuids| values are
    // appended, while |service_data| and |manufacturer_data| are merged into the
    // existing property values. Has no effect if the fake device does not exist.
    void UpdateServiceAndManufacturerData(
        const dbus::ObjectPath& object_path,
        const std::vector<std::string>& service_uuids,
        const std::map<std::string, std::vector<uint8_t>>& service_data,
        const std::map<uint16_t, std::vector<uint8_t>>& manufacturer_data);
  
    // Updates the EIR property of fake device with object path |object_path| to
    // |eir|, if the fake device exists.
    void UpdateEIR(const dbus::ObjectPath& object_path,
                   const std::vector<uint8_t>& eir);
  
    // Adds a pending prepare write request to |object_path|.
    void AddPrepareWriteRequest(const dbus::ObjectPath& object_path,
                                const std::vector<uint8_t>& value);
  
    static const char kTestPinCode[];
    static const int kTestPassKey;
  
    static const char kPairingMethodNone[];
    static const char kPairingMethodPinCode[];
    static const char kPairingMethodPassKey[];
  
    static const char kPairingActionConfirmation[];
    static const char kPairingActionDisplay[];
    static const char kPairingActionFail[];
    static const char kPairingActionRequest[];
  
    // Object paths, names, addresses and bluetooth classes of the devices
    // we can emulate.
    static const char kPairedDevicePath[];
    static const char kPairedDeviceName[];
    static const char kPairedDeviceAlias[];
    static const char kPairedDeviceAddress[];
    static const uint32_t kPairedDeviceClass;
  
    static const char kLegacyAutopairPath[];
    static const char kLegacyAutopairName[];
    static const char kLegacyAutopairAddress[];
    static const uint32_t kLegacyAutopairClass;
  
    static const char kDisplayPinCodePath[];
    static const char kDisplayPinCodeName[];
    static const char kDisplayPinCodeAddress[];
    static const uint32_t kDisplayPinCodeClass;
  
    static const char kVanishingDevicePath[];
    static const char kVanishingDeviceName[];
    static const char kVanishingDeviceAddress[];
    static const uint32_t kVanishingDeviceClass;
  
    static const char kConnectUnpairablePath[];
    static const char kConnectUnpairableName[];
    static const char kConnectUnpairableAddress[];
    static const uint32_t kConnectUnpairableClass;
  
    static const char kDisplayPasskeyPath[];
    static const char kDisplayPasskeyName[];
    static const char kDisplayPasskeyAddress[];
    static const uint32_t kDisplayPasskeyClass;
  
    static const char kRequestPinCodePath[];
    static const char kRequestPinCodeName[];
    static const char kRequestPinCodeAddress[];
    static const uint32_t kRequestPinCodeClass;
  
    static const char kConfirmPasskeyPath[];
    static const char kConfirmPasskeyName[];
    static const char kConfirmPasskeyAddress[];
    static const uint32_t kConfirmPasskeyClass;
  
    static const char kRequestPasskeyPath[];
    static const char kRequestPasskeyName[];
    static const char kRequestPasskeyAddress[];
    static const uint32_t kRequestPasskeyClass;
  
    static const char kUnconnectableDevicePath[];
    static const char kUnconnectableDeviceName[];
    static const char kUnconnectableDeviceAddress[];
    static const uint32_t kUnconnectableDeviceClass;
  
    static const char kUnpairableDevicePath[];
    static const char kUnpairableDeviceName[];
    static const char kUnpairableDeviceAddress[];
    static const uint32_t kUnpairableDeviceClass;
  
    static const char kJustWorksPath[];
    static const char kJustWorksName[];
    static const char kJustWorksAddress[];
    static const uint32_t kJustWorksClass;
  
    static const char kLowEnergyPath[];
    static const char kLowEnergyName[];
    static const char kLowEnergyAddress[];
    static const uint32_t kLowEnergyClass;
  
    static const char kDualPath[];
    static const char kDualName[];
    static const char kDualAddress[];
  
    static const char kPairedUnconnectableDevicePath[];
    static const char kPairedUnconnectableDeviceName[];
    static const char kPairedUnconnectableDeviceAlias[];
    static const char kPairedUnconnectableDeviceAddress[];
    static const uint32_t kPairedUnconnectableDeviceClass;
  
    static const char kConnectedTrustedNotPairedDevicePath[];
    static const char kConnectedTrustedNotPairedDeviceAddress[];
    static const char kConnectedTrustedNotPairedDeviceName[];
    static const uint32_t kConnectedTrustedNotPairedDeviceClass;
  
   private:
    // Property callback passed when we create Properties* structures.
    void OnPropertyChanged(const dbus::ObjectPath& object_path,
                           const std::string& property_name);
  
    void DiscoverySimulationTimer();
    void IncomingPairingSimulationTimer();
  
    void CompleteSimulatedPairing(const dbus::ObjectPath& object_path,
                                  base::OnceClosure callback,
                                  ErrorCallback error_callback);
    void TimeoutSimulatedPairing(const dbus::ObjectPath& object_path,
                                 ErrorCallback error_callback);
    void CancelSimulatedPairing(const dbus::ObjectPath& object_path,
                                ErrorCallback error_callback);
    void RejectSimulatedPairing(const dbus::ObjectPath& object_path,
                                ErrorCallback error_callback);
    void FailSimulatedPairing(const dbus::ObjectPath& object_path,
                              ErrorCallback error_callback);
    void AddInputDeviceIfNeeded(const dbus::ObjectPath& object_path,
                                Properties* properties);
  
    // If fake device with |object_path| exists, sets its inquiry RSSI property
    // to false and notifies that the property changed.
    void InvalidateDeviceRSSI(const dbus::ObjectPath& object_path);
  
    void PinCodeCallback(const dbus::ObjectPath& object_path,
                         base::OnceClosure callback,
                         ErrorCallback error_callback,
                         BluetoothAgentServiceProvider::Delegate::Status status,
                         const std::string& pincode);
    void PasskeyCallback(const dbus::ObjectPath& object_path,
                         base::OnceClosure callback,
                         ErrorCallback error_callback,
                         BluetoothAgentServiceProvider::Delegate::Status status,
                         uint32_t passkey);
    void ConfirmationCallback(
        const dbus::ObjectPath& object_path,
        base::OnceClosure callback,
        ErrorCallback error_callback,
        BluetoothAgentServiceProvider::Delegate::Status status);
    void SimulateKeypress(uint16_t entered,
                          const dbus::ObjectPath& object_path,
                          base::OnceClosure callback,
                          ErrorCallback error_callback);
  
    void ConnectionCallback(
        const dbus::ObjectPath& object_path,
        base::OnceClosure callback,
        ErrorCallback error_callback,
        BluetoothProfileServiceProvider::Delegate::Status status);
    void DisconnectionCallback(
        const dbus::ObjectPath& object_path,
        base::OnceClosure callback,
        ErrorCallback error_callback,
        BluetoothProfileServiceProvider::Delegate::Status status);
  
    // List of observers interested in event notifications from us.
    base::ObserverList<Observer>::Unchecked observers_;
  
    using PropertiesMap =
        std::map<const dbus::ObjectPath, std::unique_ptr<Properties>>;
    PropertiesMap properties_map_;
    std::vector<dbus::ObjectPath> device_list_;
  
    // Properties which are used to decied which method of pairing should
    // be done on request.
    using PairingOptionsMap = std::map<const dbus::ObjectPath,
                                       std::unique_ptr<SimulatedPairingOptions>>;
    PairingOptionsMap pairing_options_map_;
  
    int simulation_interval_ms_;
    uint32_t discovery_simulation_step_;
    uint32_t incoming_pairing_simulation_step_;
    bool pairing_cancelled_;
  
    int16_t connection_rssi_;
    int16_t transmit_power_;
    int16_t max_transmit_power_;
  
    // Controls the fake behavior to allow more extensive UI testing without
    // having to cycle the discovery simulation.
    bool delay_start_discovery_;
  
    // Pending prepare write requests.
    std::vector<std::pair<dbus::ObjectPath, std::vector<uint8_t>>>
        prepare_write_requests_;
  
    bool should_leave_connections_pending_;
  };
  
  }  // namespace bluez
  
  #endif  // DEVICE_BLUETOOTH_DBUS_FAKE_BLUETOOTH_DEVICE_CLIENT_H_
  