blob: 043defb1a41785e6d76702fa00164a6c9f7a510e [file] [log] [blame]
// Copyright 2017 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 CHROMEOS_COMPONENTS_TETHER_CONNECT_TETHERING_OPERATION_H_
#define CHROMEOS_COMPONENTS_TETHER_CONNECT_TETHERING_OPERATION_H_
#include <stdint.h>
#include <map>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/time/clock.h"
#include "base/time/time.h"
#include "chromeos/components/multidevice/remote_device_ref.h"
#include "chromeos/components/tether/message_transfer_operation.h"
namespace chromeos {
namespace device_sync {
class DeviceSyncClient;
} // namespace device_sync
namespace secure_channel {
class SecureChannelClient;
} // namespace secure_channel
namespace tether {
class MessageWrapper;
class TetherHostResponseRecorder;
// Operation used to request that a tether host share its Internet connection.
// Attempts a connection to the RemoteDevice passed to its constructor and
// notifies observers when the RemoteDevice sends a response.
class ConnectTetheringOperation : public MessageTransferOperation {
public:
// Includes all error codes of ConnectTetheringResponse_ResponseCode, but
// includes extra values: |COULD_NOT_CONNECT_TO_PHONE|,
// |INVALID_HOTSPOT_CREDENTIALS|, |SUCCESSFUL_REQUEST_BUT_NO_RESPONSE|, and
// |UNRECOGNIZED_RESPONSE_ERROR|.
enum HostResponseErrorCode {
PROVISIONING_FAILED = 0,
TETHERING_TIMEOUT = 1,
TETHERING_UNSUPPORTED = 2,
NO_CELL_DATA = 3,
ENABLING_HOTSPOT_FAILED = 4,
ENABLING_HOTSPOT_TIMEOUT = 5,
UNKNOWN_ERROR = 6,
NO_RESPONSE = 7,
INVALID_HOTSPOT_CREDENTIALS = 8,
UNRECOGNIZED_RESPONSE_ERROR = 9
};
class Factory {
public:
static std::unique_ptr<ConnectTetheringOperation> NewInstance(
multidevice::RemoteDeviceRef device_to_connect,
device_sync::DeviceSyncClient* device_sync_client,
secure_channel::SecureChannelClient* secure_channel_client,
TetherHostResponseRecorder* tether_host_response_recorder,
bool setup_required);
static void SetInstanceForTesting(Factory* factory);
protected:
virtual std::unique_ptr<ConnectTetheringOperation> BuildInstance(
multidevice::RemoteDeviceRef devices_to_connect,
device_sync::DeviceSyncClient* device_sync_client,
secure_channel::SecureChannelClient* secure_channel_client,
TetherHostResponseRecorder* tether_host_response_recorder,
bool setup_required);
private:
static Factory* factory_instance_;
};
class Observer {
public:
virtual void OnConnectTetheringRequestSent(
multidevice::RemoteDeviceRef remote_device) = 0;
virtual void OnSuccessfulConnectTetheringResponse(
multidevice::RemoteDeviceRef remote_device,
const std::string& ssid,
const std::string& password) = 0;
virtual void OnConnectTetheringFailure(
multidevice::RemoteDeviceRef remote_device,
HostResponseErrorCode error_code) = 0;
};
~ConnectTetheringOperation() override;
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
protected:
ConnectTetheringOperation(
multidevice::RemoteDeviceRef device_to_connect,
device_sync::DeviceSyncClient* device_sync_client,
secure_channel::SecureChannelClient* secure_channel_client,
TetherHostResponseRecorder* tether_host_response_recorder,
bool setup_required);
// MessageTransferOperation:
void OnDeviceAuthenticated(
multidevice::RemoteDeviceRef remote_device) override;
void OnMessageReceived(std::unique_ptr<MessageWrapper> message_wrapper,
multidevice::RemoteDeviceRef remote_device) override;
void OnOperationFinished() override;
MessageType GetMessageTypeForConnection() override;
void OnMessageSent(int sequence_number) override;
uint32_t GetMessageTimeoutSeconds() override;
void NotifyConnectTetheringRequestSent();
void NotifyObserversOfSuccessfulResponse(const std::string& ssid,
const std::string& password);
void NotifyObserversOfConnectionFailure(HostResponseErrorCode error_code);
private:
friend class ConnectTetheringOperationTest;
FRIEND_TEST_ALL_PREFIXES(ConnectTetheringOperationTest,
SuccessWithValidResponse);
FRIEND_TEST_ALL_PREFIXES(ConnectTetheringOperationTest,
SuccessButInvalidResponse);
FRIEND_TEST_ALL_PREFIXES(ConnectTetheringOperationTest, UnknownError);
FRIEND_TEST_ALL_PREFIXES(ConnectTetheringOperationTest, ProvisioningFailed);
FRIEND_TEST_ALL_PREFIXES(ConnectTetheringOperationTest,
NotifyConnectTetheringRequest);
FRIEND_TEST_ALL_PREFIXES(ConnectTetheringOperationTest,
GetMessageTimeoutSeconds);
FRIEND_TEST_ALL_PREFIXES(ConnectTetheringOperationTest,
MessageSentOnceAuthenticated);
HostResponseErrorCode ConnectTetheringResponseCodeToHostResponseErrorCode(
ConnectTetheringResponse_ResponseCode error_code);
void SetClockForTest(base::Clock* clock_for_test);
// The amount of time this operation will wait for a response. The timeout
// values are different depending on whether setup is needed on the host.
static const uint32_t kSetupNotRequiredResponseTimeoutSeconds;
static const uint32_t kSetupRequiredResponseTimeoutSeconds;
multidevice::RemoteDeviceRef remote_device_;
TetherHostResponseRecorder* tether_host_response_recorder_;
base::Clock* clock_;
int connect_message_sequence_number_ = -1;
bool setup_required_;
// These values are saved in OnMessageReceived() and returned in
// OnOperationFinished().
std::string ssid_to_return_;
std::string password_to_return_;
HostResponseErrorCode error_code_to_return_;
base::Time connect_tethering_request_start_time_;
base::ObserverList<Observer>::Unchecked observer_list_;
DISALLOW_COPY_AND_ASSIGN(ConnectTetheringOperation);
};
} // namespace tether
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_TETHER_CONNECT_TETHERING_OPERATION_H_