Commit c8aad835 authored by Ovidio Henriquez's avatar Ovidio Henriquez Committed by Commit Bot

bluetooth: SetNextUnsubscribeFromNotifications

This change implements the SetNextUnsubscribeFromNotifications function
for fake characteristics.

BUG=569709

Change-Id: I99c59a4caffd524e727921fcb54f48cc868d545f
Reviewed-on: https://chromium-review.googlesource.com/988223
Commit-Queue: Ovidio Henriquez <odejesush@chromium.org>
Reviewed-by: default avatarOliver Chang <ochang@chromium.org>
Reviewed-by: default avatarGiovanni Ortuño Urquidi <ortuno@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548544}
parent 5f83d227
...@@ -288,6 +288,28 @@ interface FakeCentral { ...@@ -288,6 +288,28 @@ interface FakeCentral {
string service_id, string service_id,
string peripheral_address) => (bool success); string peripheral_address) => (bool success);
// Sets the next unsubscribe from notifications response for characteristic
// with |characteristic_id| in |service_id| and in |peripheral_address| to
// |code|. |code| could be a GATT Error Response from BT 4.2 Vol 3
// Part F 3.4.1.1 Error Response or a number outside that range returned by
// specific platforms e.g. Android returns 0x101 to signal a GATT failure.
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#GATT_FAILURE
// Calls callback with false if there was any error when simulating the next
// response.
SetNextUnsubscribeFromNotificationsResponse(
uint16 gatt_code,
string characteristic_id,
string service_id,
string peripheral_address) => (bool success);
// Returns whether or not a client has subscribed to notifications for a
// characteristic with |characteristic_id| in |service_id| in
// |peripheral_address|. If the value can't be retrieved, calls its callback
// with false.
IsNotifying(string characteristic_id,
string service_id,
string peripheral_address) => (bool success, bool is_notifying);
// Gets the last successfully written value to the characteristic with // Gets the last successfully written value to the characteristic with
// |characteristics_id| in |service_id| and in |peripheral_address|. // |characteristics_id| in |service_id| and in |peripheral_address|.
// If the value can't be retrieved calls its callback with false. Calls its // If the value can't be retrieved calls its callback with false. Calls its
......
...@@ -317,6 +317,38 @@ void FakeCentral::SetNextSubscribeToNotificationsResponse( ...@@ -317,6 +317,38 @@ void FakeCentral::SetNextSubscribeToNotificationsResponse(
std::move(callback).Run(true); std::move(callback).Run(true);
} }
void FakeCentral::SetNextUnsubscribeFromNotificationsResponse(
uint16_t gatt_code,
const std::string& characteristic_id,
const std::string& service_id,
const std::string& peripheral_address,
SetNextUnsubscribeFromNotificationsResponseCallback callback) {
FakeRemoteGattCharacteristic* fake_remote_gatt_characteristic =
GetFakeRemoteGattCharacteristic(peripheral_address, service_id,
characteristic_id);
if (fake_remote_gatt_characteristic == nullptr) {
std::move(callback).Run(false);
}
fake_remote_gatt_characteristic->SetNextUnsubscribeFromNotificationsResponse(
gatt_code);
std::move(callback).Run(true);
}
void FakeCentral::IsNotifying(const std::string& characteristic_id,
const std::string& service_id,
const std::string& peripheral_address,
IsNotifyingCallback callback) {
FakeRemoteGattCharacteristic* fake_remote_gatt_characteristic =
GetFakeRemoteGattCharacteristic(peripheral_address, service_id,
characteristic_id);
if (!fake_remote_gatt_characteristic) {
std::move(callback).Run(false, false);
}
std::move(callback).Run(true, fake_remote_gatt_characteristic->IsNotifying());
}
void FakeCentral::GetLastWrittenCharacteristicValue( void FakeCentral::GetLastWrittenCharacteristicValue(
const std::string& characteristic_id, const std::string& characteristic_id,
const std::string& service_id, const std::string& service_id,
......
...@@ -98,7 +98,17 @@ class FakeCentral : public mojom::FakeCentral, public device::BluetoothAdapter { ...@@ -98,7 +98,17 @@ class FakeCentral : public mojom::FakeCentral, public device::BluetoothAdapter {
const std::string& characteristic_id, const std::string& characteristic_id,
const std::string& service_id, const std::string& service_id,
const std::string& peripheral_address, const std::string& peripheral_address,
SetNextWriteCharacteristicResponseCallback callback) override; SetNextSubscribeToNotificationsResponseCallback callback) override;
void SetNextUnsubscribeFromNotificationsResponse(
uint16_t gatt_code,
const std::string& characteristic_id,
const std::string& service_id,
const std::string& peripheral_address,
SetNextUnsubscribeFromNotificationsResponseCallback callback) override;
void IsNotifying(const std::string& characteristic_id,
const std::string& service_id,
const std::string& peripheral_address,
IsNotifyingCallback callback) override;
void GetLastWrittenCharacteristicValue( void GetLastWrittenCharacteristicValue(
const std::string& characteristic_id, const std::string& characteristic_id,
const std::string& service_id, const std::string& service_id,
......
...@@ -91,6 +91,12 @@ void FakeRemoteGattCharacteristic::SetNextSubscribeToNotificationsResponse( ...@@ -91,6 +91,12 @@ void FakeRemoteGattCharacteristic::SetNextSubscribeToNotificationsResponse(
next_subscribe_to_notifications_response_.emplace(gatt_code); next_subscribe_to_notifications_response_.emplace(gatt_code);
} }
void FakeRemoteGattCharacteristic::SetNextUnsubscribeFromNotificationsResponse(
uint16_t gatt_code) {
DCHECK(!next_unsubscribe_from_notifications_response_);
next_unsubscribe_from_notifications_response_.emplace(gatt_code);
}
bool FakeRemoteGattCharacteristic::AllResponsesConsumed() { bool FakeRemoteGattCharacteristic::AllResponsesConsumed() {
// TODO(crbug.com/569709): Update this when // TODO(crbug.com/569709): Update this when
// SetNextUnsubscribeFromNotificationsResponse is implemented. // SetNextUnsubscribeFromNotificationsResponse is implemented.
...@@ -192,7 +198,11 @@ void FakeRemoteGattCharacteristic::UnsubscribeFromNotifications( ...@@ -192,7 +198,11 @@ void FakeRemoteGattCharacteristic::UnsubscribeFromNotifications(
device::BluetoothRemoteGattDescriptor* ccc_descriptor, device::BluetoothRemoteGattDescriptor* ccc_descriptor,
const base::Closure& callback, const base::Closure& callback,
const ErrorCallback& error_callback) { const ErrorCallback& error_callback) {
NOTREACHED(); base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&FakeRemoteGattCharacteristic::
DispatchUnsubscribeFromNotificationsResponse,
weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
} }
void FakeRemoteGattCharacteristic::DispatchReadResponse( void FakeRemoteGattCharacteristic::DispatchReadResponse(
...@@ -258,4 +268,23 @@ void FakeRemoteGattCharacteristic::DispatchSubscribeToNotificationsResponse( ...@@ -258,4 +268,23 @@ void FakeRemoteGattCharacteristic::DispatchSubscribeToNotificationsResponse(
} }
} }
void FakeRemoteGattCharacteristic::DispatchUnsubscribeFromNotificationsResponse(
const base::Closure& callback,
const ErrorCallback& error_callback) {
DCHECK(next_unsubscribe_from_notifications_response_);
uint16_t gatt_code = next_unsubscribe_from_notifications_response_.value();
next_unsubscribe_from_notifications_response_.reset();
switch (gatt_code) {
case mojom::kGATTSuccess:
callback.Run();
break;
case mojom::kGATTInvalidHandle:
error_callback.Run(device::BluetoothGattService::GATT_ERROR_FAILED);
break;
default:
NOTREACHED();
}
}
} // namespace bluetooth } // namespace bluetooth
...@@ -59,6 +59,11 @@ class FakeRemoteGattCharacteristic ...@@ -59,6 +59,11 @@ class FakeRemoteGattCharacteristic
// call its error callback. // call its error callback.
void SetNextSubscribeToNotificationsResponse(uint16_t gatt_code); void SetNextSubscribeToNotificationsResponse(uint16_t gatt_code);
// If |gatt_code| is mojom::kGATTSuccess the next unsubscribe to notifications
// with response request will call its success callback. Otherwise it will
// call its error callback.
void SetNextUnsubscribeFromNotificationsResponse(uint16_t gatt_code);
// Returns true if there are no pending responses for this characteristc or // Returns true if there are no pending responses for this characteristc or
// any of its descriptors. // any of its descriptors.
bool AllResponsesConsumed(); bool AllResponsesConsumed();
...@@ -108,6 +113,9 @@ class FakeRemoteGattCharacteristic ...@@ -108,6 +113,9 @@ class FakeRemoteGattCharacteristic
void DispatchSubscribeToNotificationsResponse( void DispatchSubscribeToNotificationsResponse(
const base::Closure& callback, const base::Closure& callback,
const ErrorCallback& error_callback); const ErrorCallback& error_callback);
void DispatchUnsubscribeFromNotificationsResponse(
const base::Closure& callback,
const ErrorCallback& error_callback);
const std::string characteristic_id_; const std::string characteristic_id_;
const device::BluetoothUUID characteristic_uuid_; const device::BluetoothUUID characteristic_uuid_;
...@@ -130,6 +138,10 @@ class FakeRemoteGattCharacteristic ...@@ -130,6 +138,10 @@ class FakeRemoteGattCharacteristic
// SubscribeToNotifications is called. // SubscribeToNotifications is called.
base::Optional<uint16_t> next_subscribe_to_notifications_response_; base::Optional<uint16_t> next_subscribe_to_notifications_response_;
// Used to decide which callback should be called when
// UnsubscribeFromNotifications is called.
base::Optional<uint16_t> next_unsubscribe_from_notifications_response_;
size_t last_descriptor_id_; size_t last_descriptor_id_;
using FakeDescriptorMap = using FakeDescriptorMap =
......
...@@ -6,20 +6,26 @@ ...@@ -6,20 +6,26 @@
<script src="../../../external/wpt/bluetooth/resources/bluetooth-helpers.js"></script> <script src="../../../external/wpt/bluetooth/resources/bluetooth-helpers.js"></script>
<script> <script>
'use strict'; 'use strict';
bluetooth_test(() => { const test_desc = 'The characteristic should be able to start and stop ' +
return setBluetoothFakeAdapter('HeartRateAdapter') 'notifications multiple times in a row.';
.then(() => requestDeviceWithTrustedClick({ let characteristic, fake_characteristic;
filters: [{services: ['heart_rate']}]})) let startStopNotifications = () => {
.then(device => device.gatt.connect()) return fake_characteristic.setNextSubscribeToNotificationsResponse(
.then(gattServer => gattServer.getPrimaryService('heart_rate')) HCI_SUCCESS)
.then(service => service.getCharacteristic('heart_rate_measurement')) .then(() => characteristic.startNotifications())
.then(characteristic => { .then(() => fake_characteristic.isNotifying())
return characteristic.startNotifications() .then(isNotifying => assert_true(isNotifying))
.then(() => characteristic.stopNotifications()) .then(() =>
.then(() => characteristic.startNotifications()) fake_characteristic.setNextUnsubscribeFromNotificationsResponse(
.then(() => characteristic.stopNotifications()); HCI_SUCCESS))
}); .then(() => characteristic.stopNotifications())
// TODO(ortuno): Assert that notifications are not active. .then(() => fake_characteristic.isNotifying())
// http://crbug.com/600762 .then(isNotifying => assert_false(isNotifying));
}, 'Start -> stop -> start -> stop.'); }
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({characteristic, fake_characteristic} = _))
.then(() => startStopNotifications())
.then(() => startStopNotifications()),
test_desc);
</script> </script>
...@@ -393,6 +393,30 @@ class FakeRemoteGATTCharacteristic { ...@@ -393,6 +393,30 @@ class FakeRemoteGATTCharacteristic {
if (!success) throw 'setNextSubscribeToNotificationsResponse failed'; if (!success) throw 'setNextSubscribeToNotificationsResponse failed';
} }
// Sets the next unsubscribe to notifications response for characteristic with
// |characteristic_id| in |service_id| and in |peripheral_address| to
// |code|. |code| could be a GATT Error Response from BT 4.2 Vol 3 Part F
// 3.4.1.1 Error Response or a number outside that range returned by
// specific platforms e.g. Android returns 0x101 to signal a GATT failure.
async setNextUnsubscribeFromNotificationsResponse(gatt_code) {
let {success} =
await this.fake_central_ptr_.setNextUnsubscribeFromNotificationsResponse(
gatt_code, ...this.ids_);
if (!success) throw 'setNextUnsubscribeToNotificationsResponse failed';
}
// Returns true if notifications from the characteristic have been subscribed
// to.
async isNotifying() {
let {success, isNotifying} =
await this.fake_central_ptr_.isNotifying(...this.ids_);
if (!success) throw 'isNotifying failed';
return isNotifying;
}
// Gets the last successfully written value to the characteristic. // Gets the last successfully written value to the characteristic.
// Returns null if no value has yet been written to the characteristic. // Returns null if no value has yet been written to the characteristic.
async getLastWrittenValue() { async getLastWrittenValue() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment