Chromium Code Reviews| Index: components/proximity_auth/ble/bluetooth_low_energy_connection.cc |
| diff --git a/components/proximity_auth/ble/bluetooth_low_energy_connection.cc b/components/proximity_auth/ble/bluetooth_low_energy_connection.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..bb671b1a04b45c7881a5d1835e7a93b5c9920107 |
| --- /dev/null |
| +++ b/components/proximity_auth/ble/bluetooth_low_energy_connection.cc |
| @@ -0,0 +1,274 @@ |
| +// Copyright 2015 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. |
| + |
| +#include "components/proximity_auth/ble/bluetooth_low_energy_connection.h" |
| + |
| +#include "base/bind.h" |
| +#include "base/memory/ref_counted.h" |
| +#include "base/memory/weak_ptr.h" |
| +#include "components/proximity_auth/connection_finder.h" |
| +#include "components/proximity_auth/ble/fake_wire_message.h" |
| +#include "components/proximity_auth/wire_message.h" |
| +#include "device/bluetooth/bluetooth_adapter.h" |
| +#include "device/bluetooth/bluetooth_device.h" |
| +#include "device/bluetooth/bluetooth_gatt_characteristic.h" |
| +#include "device/bluetooth/bluetooth_gatt_connection.h" |
| +#include "device/bluetooth/bluetooth_gatt_notify_session.h" |
| +#include "device/bluetooth/bluetooth_uuid.h" |
| + |
| +using device::BluetoothAdapter; |
| +using device::BluetoothDevice; |
| +using device::BluetoothGattConnection; |
| +using device::BluetoothGattService; |
| +using device::BluetoothGattCharacteristic; |
| +using device::BluetoothGattNotifySession; |
| +using device::BluetoothUUID; |
| + |
| +namespace proximity_auth { |
| + |
| +BluetoothLowEnergyConnection::BluetoothLowEnergyConnection( |
| + const RemoteDevice& device, |
| + scoped_refptr<device::BluetoothAdapter> adapter, |
| + BluetoothUUID remote_service_uuid, |
| + scoped_ptr<BluetoothGattConnection> gatt_connection) |
| + : Connection(device), |
| + adapter_(adapter), |
| + remote_service_uuid_(remote_service_uuid), |
| + connection_(gatt_connection.Pass()), |
| + notify_session_pending_(false), |
| + weak_ptr_factory_(this) { |
| + if (connection_) { |
|
msarda
2015/05/05 11:56:13
Can |connection_| be null? If not, then it is bett
sacomoto
2015/05/06 13:47:58
Done.
|
| + SetStatus(IN_PROGRESS); |
| + } |
| + |
| + if (adapter_) { |
|
msarda
2015/05/05 11:56:14
DCHECK(adapter_)?
sacomoto
2015/05/06 13:47:58
Done.
|
| + adapter_->AddObserver(this); |
| + } |
| +} |
| + |
| +BluetoothLowEnergyConnection::~BluetoothLowEnergyConnection() { |
| + Disconnect(); |
| + if (adapter_) { |
| + adapter_->RemoveObserver(this); |
| + adapter_ = NULL; |
| + } |
| +} |
| + |
| +void BluetoothLowEnergyConnection::Connect() { |
| + NOTREACHED(); |
| +} |
| + |
| +void BluetoothLowEnergyConnection::Disconnect() { |
| + StopNotifySession(); |
| + if (connection_) { |
| + connection_.reset(); |
| + BluetoothDevice* device = GetRemoteDevice(); |
| + if (device) { |
| + VLOG(1) << "Forget device " << device->GetAddress(); |
| + device->Forget(base::Bind(&base::DoNothing)); |
|
msarda
2015/05/05 11:56:14
Please add a comment that disconnect actually forg
sacomoto
2015/05/06 13:47:58
Done.
|
| + } |
| + } |
| +} |
| + |
| +// TODO(sacomoto): Send a Socketeer incoming signal. Implement a sender with |
|
msarda
2015/05/05 11:56:13
Remove all reference to Socketeer.
sacomoto
2015/05/06 13:47:58
Done.
|
| +// full support for messages larger than a single characteristic value. |
| +void BluetoothLowEnergyConnection::SendMessageImpl( |
| + scoped_ptr<WireMessage> message) { |
| + DCHECK(!GetGattCharacteristic(to_peripheral_char_id_)); |
| + VLOG(1) << "Sending message " << message->Serialize(); |
| + |
| + std::string serialized_message = message->Serialize(); |
| + std::vector<uint8> bytes(serialized_message.begin(), |
| + serialized_message.end()); |
| + |
| + GetGattCharacteristic(to_peripheral_char_id_) |
| + ->WriteRemoteCharacteristic( |
| + bytes, base::Bind(&base::DoNothing), |
| + base::Bind( |
| + &BluetoothLowEnergyConnection::OnWriteRemoteCharacteristicError, |
| + weak_ptr_factory_.GetWeakPtr())); |
| +} |
| + |
| +void BluetoothLowEnergyConnection::DeviceRemoved(BluetoothAdapter* adapter, |
| + BluetoothDevice* device) { |
| + if (device && device->GetAddress() == remote_device_address()) { |
| + VLOG(1) << "device removed " << remote_device_address(); |
|
msarda
2015/05/05 11:56:13
Log should state with CAPS:
s/device/Device
sacomoto
2015/05/06 13:47:57
Done.
|
| + Disconnect(); |
| + } |
| +} |
| + |
| +void BluetoothLowEnergyConnection::GattDiscoveryCompleteForService( |
| + BluetoothAdapter* adapter, |
| + BluetoothGattService* service) { |
| + if (service && service->GetUUID() == remote_service_uuid_) { |
| + VLOG(1) << "All characteristics discovered for " |
| + << remote_service_uuid_.canonical_value(); |
| + |
| + std::vector<device::BluetoothGattCharacteristic*> characteristics = |
| + service->GetCharacteristics(); |
| + for (auto iter = characteristics.begin(); iter != characteristics.end(); |
| + iter++) { |
| + HandleCharacteristicUpdate(*iter); |
| + } |
| + |
| + if (to_peripheral_char_id_.empty() || from_peripheral_char_id_.empty()) { |
| + VLOG(1) << "Connection error, missing characteristics for service."; |
|
msarda
2015/05/05 11:56:13
s/service/Smart Lock service
msarda
2015/05/05 11:56:13
Please also log which one of |to_peripheral_char_i
sacomoto
2015/05/06 13:47:58
Done.
sacomoto
2015/05/06 13:47:58
Done.
|
| + Disconnect(); |
| + } |
| + } |
| +} |
| + |
| +void BluetoothLowEnergyConnection::GattCharacteristicAdded( |
| + BluetoothAdapter* adapter, |
| + BluetoothGattCharacteristic* characteristic) { |
| + VLOG(1) << "new char found: " << characteristic->GetUUID().canonical_value(); |
| + HandleCharacteristicUpdate(characteristic); |
| +} |
| + |
| +// TODO(sacomoto): Parse the Sockeeter incoming signal. Implement a receiver |
|
msarda
2015/05/05 11:56:13
Remove Socketeer.
sacomoto
2015/05/06 13:47:58
Done.
|
| +// with full suport for messages larger than a single characteristic value. |
| +void BluetoothLowEnergyConnection::GattCharacteristicValueChanged( |
| + BluetoothAdapter* adapter, |
| + BluetoothGattCharacteristic* characteristic, |
| + const std::vector<uint8>& value) { |
| + VLOG(1) << "Characteristic value changed: " |
| + << characteristic->GetUUID().canonical_value(); |
| + if (characteristic->GetIdentifier() == from_peripheral_char_id_) { |
| + std::string message(value.begin(), value.end()); |
| + VLOG(1) << "value: " << message; |
| + // TODO(sacomoto): Actually handle the message and call OnBytesReceived when |
| + // complete. |
| + } |
| +} |
| + |
| +scoped_ptr<WireMessage> BluetoothLowEnergyConnection::DeserializeWireMessage( |
| + bool* is_incomplete_message) { |
| + return FakeWireMessage::Deserialize(received_bytes(), is_incomplete_message); |
| +} |
| + |
| +void BluetoothLowEnergyConnection::HandleCharacteristicUpdate( |
| + BluetoothGattCharacteristic* characteristic) { |
| + // Checks if |characteristic| is equal to |from_peripheral_char_| or |
| + // |to_peripheral_char_| are present. |
| + UpdateCharacteristicsStatus(characteristic); |
| + |
| + // Starts a notify session for |from_peripheral_char_|. |
| + if (characteristic->GetIdentifier() == from_peripheral_char_id_) |
| + StartNotifySession(); |
| + |
| + // Checks if the connection is complete. |
| + CompleteConnection(); |
| +} |
| + |
| +void BluetoothLowEnergyConnection::CompleteConnection() { |
| + if (status() == IN_PROGRESS && !to_peripheral_char_id_.empty() && |
| + !from_peripheral_char_id_.empty() && notify_session_) { |
| + VLOG(1) << "Connection completed"; |
| + SetStatus(CONNECTED); |
| + SendInviteToConnectSignal(); |
|
msarda
2015/05/05 11:56:13
Should we wait for a reply to invite signal before
sacomoto
2015/05/06 13:47:58
Done.
|
| + } |
| +} |
| + |
| +void BluetoothLowEnergyConnection::StartNotifySession() { |
| + BluetoothGattCharacteristic* characteristic = |
| + GetGattCharacteristic(from_peripheral_char_id_); |
| + if (!characteristic) { |
| + VLOG(1) << "Characteristic " << from_peripheral_char_ << " not found."; |
| + return; |
| + } |
| + |
| + if (notify_session_ || notify_session_pending_) { |
| + VLOG(1) << "Notify session already started."; |
| + return; |
| + } |
| + |
| + notify_session_pending_ = true; |
| + characteristic->StartNotifySession( |
| + base::Bind(&BluetoothLowEnergyConnection::OnNotifySessionStarted, |
| + weak_ptr_factory_.GetWeakPtr()), |
| + base::Bind(&BluetoothLowEnergyConnection::OnNotifySessionError, |
| + weak_ptr_factory_.GetWeakPtr())); |
| +} |
| + |
| +void BluetoothLowEnergyConnection::OnNotifySessionError( |
| + BluetoothGattService::GattErrorCode error) { |
| + VLOG(1) << "Error starting notification session: " << error; |
| + notify_session_pending_ = false; |
| +} |
| + |
| +void BluetoothLowEnergyConnection::OnNotifySessionStarted( |
| + scoped_ptr<BluetoothGattNotifySession> notify_session) { |
| + VLOG(1) << "Notification session started " |
| + << notify_session->GetCharacteristicIdentifier(); |
| + notify_session_ = notify_session.Pass(); |
| + notify_session_pending_ = false; |
| + |
| + // Checks if the connection is complete. |
| + CompleteConnection(); |
| +} |
| + |
| +void BluetoothLowEnergyConnection::StopNotifySession() { |
| + if (notify_session_) { |
| + notify_session_->Stop(base::Bind(&base::DoNothing)); |
| + notify_session_.reset(); |
| + } |
| +} |
| + |
| +void BluetoothLowEnergyConnection::OnWriteRemoteCharacteristicError( |
| + BluetoothGattService::GattErrorCode error) { |
| + VLOG(1) << "Error writing characteristic" << to_peripheral_char_; |
| +} |
| + |
| +void BluetoothLowEnergyConnection::SendInviteToConnectSignal() { |
| + // From Socketeer library: connect signal is 0 (32-bit int). |
| + const char connect_signal[4] = {}; |
| + SendMessage(scoped_ptr<FakeWireMessage>(new FakeWireMessage(connect_signal))); |
| +} |
| + |
| +void BluetoothLowEnergyConnection::UpdateCharacteristicsStatus( |
| + BluetoothGattCharacteristic* characteristic) { |
| + if (characteristic) { |
| + std::string canonical_value = characteristic->GetUUID().canonical_value(); |
| + VLOG(1) << canonical_value; |
| + if (to_peripheral_char_ == canonical_value) { |
| + to_peripheral_char_id_ = characteristic->GetIdentifier(); |
| + } |
| + if (from_peripheral_char_ == canonical_value) { |
| + from_peripheral_char_id_ = characteristic->GetIdentifier(); |
| + } |
| + BluetoothGattService* service = characteristic->GetService(); |
| + if (service && service->GetUUID() == remote_service_uuid_) |
| + remote_service_id_ = service->GetIdentifier(); |
| + } |
| +} |
| + |
| +BluetoothDevice* BluetoothLowEnergyConnection::GetRemoteDevice() { |
| + if (!adapter_ || !adapter_->IsInitialized()) { |
| + VLOG(1) << "adapter not ready"; |
| + return NULL; |
| + } |
| + return adapter_->GetDevice(remote_device_address()); |
| +} |
| + |
| +BluetoothGattService* BluetoothLowEnergyConnection::GetRemoteService() { |
| + BluetoothDevice* remote_device = GetRemoteDevice(); |
| + if (!remote_device) { |
| + VLOG(1) << "device not found"; |
| + return NULL; |
| + } |
| + return remote_device->GetGattService(remote_service_id_); |
| +} |
| + |
| +BluetoothGattCharacteristic* |
| +BluetoothLowEnergyConnection::GetGattCharacteristic( |
| + const std::string& gatt_characteristic) { |
| + BluetoothGattService* remote_service = GetRemoteService(); |
| + if (!remote_service) { |
| + VLOG(1) << "service not found"; |
| + return NULL; |
| + } |
| + return remote_service->GetCharacteristic(gatt_characteristic); |
| +} |
| + |
| +} // namespace proximity_auth |