chrome.bluetoothLowEnergy: Implement writeCharacteristicValue.

This CL implements the writeCharacteristicValue function of the
bluetoothLowEnergy API.

BUG=265663
TEST=browser_tests --gtest_filter=BluetoothLowEnergyApiTest.*

Review URL: https://codereview.chromium.org/263333003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@269509 0039d316-1c4b-4281-b951-d872f2087c98
parent be3bf145
...@@ -31,6 +31,8 @@ const char kErrorReadCharacteristicValueFailedFormat[] = ...@@ -31,6 +31,8 @@ const char kErrorReadCharacteristicValueFailedFormat[] =
const char kErrorServiceNotFoundFormat[] = "Service with ID \"%s\" not found."; const char kErrorServiceNotFoundFormat[] = "Service with ID \"%s\" not found.";
const char kErrorPlatformNotSupported[] = const char kErrorPlatformNotSupported[] =
"This operation is not supported on the current platform"; "This operation is not supported on the current platform";
const char kErrorWriteCharacteristicValueFailedFormat[] =
"Failed to write value of characteristic with ID \"%s\".";
extensions::BluetoothLowEnergyEventRouter* GetEventRouter( extensions::BluetoothLowEnergyEventRouter* GetEventRouter(
BrowserContext* context) { BrowserContext* context) {
...@@ -365,10 +367,53 @@ void BluetoothLowEnergyReadCharacteristicValueFunction::ErrorCallback() { ...@@ -365,10 +367,53 @@ void BluetoothLowEnergyReadCharacteristicValueFunction::ErrorCallback() {
} }
bool BluetoothLowEnergyWriteCharacteristicValueFunction::DoWork() { bool BluetoothLowEnergyWriteCharacteristicValueFunction::DoWork() {
// TODO(armansito): Implement. DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
SetError("Call not supported.");
BluetoothLowEnergyEventRouter* event_router =
GetEventRouter(browser_context());
// The adapter must be initialized at this point, but return an error instead
// of asserting.
if (!event_router->HasAdapter()) {
SetError(kErrorAdapterNotInitialized);
SendResponse(false);
return false;
}
scoped_ptr<apibtle::WriteCharacteristicValue::Params> params(
apibtle::WriteCharacteristicValue::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
instance_id_ = params->characteristic_id;
std::vector<uint8> value(params->value.begin(), params->value.end());
if (!event_router->WriteCharacteristicValue(
instance_id_,
value,
base::Bind(&BluetoothLowEnergyWriteCharacteristicValueFunction::
SuccessCallback,
this),
base::Bind(&BluetoothLowEnergyWriteCharacteristicValueFunction::
ErrorCallback,
this))) {
SetError(base::StringPrintf(kErrorCharacteristicNotFoundFormat,
instance_id_.c_str()));
SendResponse(false);
return false;
}
return true;
}
void BluetoothLowEnergyWriteCharacteristicValueFunction::SuccessCallback() {
results_ = apibtle::WriteCharacteristicValue::Results::Create();
SendResponse(true);
}
void BluetoothLowEnergyWriteCharacteristicValueFunction::ErrorCallback() {
SetError(base::StringPrintf(kErrorWriteCharacteristicValueFailedFormat,
instance_id_.c_str()));
SendResponse(false); SendResponse(false);
return false;
} }
bool BluetoothLowEnergyReadDescriptorValueFunction::DoWork() { bool BluetoothLowEnergyReadDescriptorValueFunction::DoWork() {
......
...@@ -197,6 +197,15 @@ class BluetoothLowEnergyWriteCharacteristicValueFunction ...@@ -197,6 +197,15 @@ class BluetoothLowEnergyWriteCharacteristicValueFunction
// BluetoothLowEnergyExtensionFunction override. // BluetoothLowEnergyExtensionFunction override.
virtual bool DoWork() OVERRIDE; virtual bool DoWork() OVERRIDE;
private:
// Success and error callbacks, called by
// BluetoothLowEnergyEventRouter::WriteCharacteristicValue.
void SuccessCallback();
void ErrorCallback();
// The instance ID of the requested characteristic.
std::string instance_id_;
}; };
class BluetoothLowEnergyReadDescriptorValueFunction class BluetoothLowEnergyReadDescriptorValueFunction
......
...@@ -26,7 +26,9 @@ using device::MockBluetoothGattService; ...@@ -26,7 +26,9 @@ using device::MockBluetoothGattService;
using extensions::BluetoothLowEnergyEventRouter; using extensions::BluetoothLowEnergyEventRouter;
using testing::Invoke; using testing::Invoke;
using testing::Return; using testing::Return;
using testing::ReturnRef;
using testing::ReturnRefOfCopy; using testing::ReturnRefOfCopy;
using testing::SaveArg;
using testing::_; using testing::_;
namespace utils = extension_function_test_utils; namespace utils = extension_function_test_utils;
...@@ -178,6 +180,18 @@ void ReadValueErrorCallback( ...@@ -178,6 +180,18 @@ void ReadValueErrorCallback(
error_callback.Run(); error_callback.Run();
} }
void WriteValueSuccessCallback(const std::vector<uint8>& value,
const base::Closure& callback,
const base::Closure& error_callback) {
callback.Run();
}
void WriteValueErrorCallback(const std::vector<uint8>& value,
const base::Closure& callback,
const base::Closure& error_callback) {
error_callback.Run();
}
IN_PROC_BROWSER_TEST_F(BluetoothLowEnergyApiTest, GetServices) { IN_PROC_BROWSER_TEST_F(BluetoothLowEnergyApiTest, GetServices) {
ResultCatcher catcher; ResultCatcher catcher;
catcher.RestrictToProfile(browser()->profile()); catcher.RestrictToProfile(browser()->profile());
...@@ -552,4 +566,46 @@ IN_PROC_BROWSER_TEST_F(BluetoothLowEnergyApiTest, ReadCharacteristicValue) { ...@@ -552,4 +566,46 @@ IN_PROC_BROWSER_TEST_F(BluetoothLowEnergyApiTest, ReadCharacteristicValue) {
event_router()->DeviceRemoved(mock_adapter_, device_.get()); event_router()->DeviceRemoved(mock_adapter_, device_.get());
} }
IN_PROC_BROWSER_TEST_F(BluetoothLowEnergyApiTest, WriteCharacteristicValue) {
ResultCatcher catcher;
catcher.RestrictToProfile(browser()->profile());
event_router()->DeviceAdded(mock_adapter_, device_.get());
event_router()->GattServiceAdded(device_.get(), service0_.get());
event_router()->GattCharacteristicAdded(service0_.get(), chrc0_.get());
EXPECT_CALL(*mock_adapter_, GetDevice(_))
.Times(3)
.WillRepeatedly(Return(device_.get()));
EXPECT_CALL(*device_, GetGattService(kTestServiceId0))
.Times(3)
.WillRepeatedly(Return(service0_.get()));
EXPECT_CALL(*service0_, GetCharacteristic(kTestCharacteristicId0))
.Times(3)
.WillRepeatedly(Return(chrc0_.get()));
std::vector<uint8> write_value;
EXPECT_CALL(*chrc0_, WriteRemoteCharacteristic(_, _, _))
.Times(2)
.WillOnce(Invoke(&WriteValueErrorCallback))
.WillOnce(
DoAll(SaveArg<0>(&write_value), Invoke(&WriteValueSuccessCallback)));
EXPECT_CALL(*chrc0_, GetValue()).Times(1).WillOnce(ReturnRef(write_value));
ExtensionTestMessageListener listener("ready", true);
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
"bluetooth_low_energy/write_characteristic_value")));
EXPECT_TRUE(listener.WaitUntilSatisfied());
listener.Reply("go");
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
event_router()->GattCharacteristicRemoved(service0_.get(), chrc0_.get());
event_router()->GattServiceRemoved(device_.get(), service0_.get());
event_router()->DeviceRemoved(mock_adapter_, device_.get());
}
} // namespace } // namespace
...@@ -343,6 +343,28 @@ bool BluetoothLowEnergyEventRouter::ReadCharacteristicValue( ...@@ -343,6 +343,28 @@ bool BluetoothLowEnergyEventRouter::ReadCharacteristicValue(
return true; return true;
} }
bool BluetoothLowEnergyEventRouter::WriteCharacteristicValue(
const std::string& instance_id,
const std::vector<uint8>& value,
const base::Closure& callback,
const base::Closure& error_callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!adapter_) {
VLOG(1) << "BluetoothAdapter not ready.";
return false;
}
BluetoothGattCharacteristic* characteristic =
FindCharacteristicById(instance_id);
if (!characteristic) {
VLOG(1) << "Characteristic not found: " << instance_id;
return false;
}
characteristic->WriteRemoteCharacteristic(value, callback, error_callback);
return true;
}
void BluetoothLowEnergyEventRouter::SetAdapterForTesting( void BluetoothLowEnergyEventRouter::SetAdapterForTesting(
device::BluetoothAdapter* adapter) { device::BluetoothAdapter* adapter) {
adapter_ = adapter; adapter_ = adapter;
......
...@@ -111,6 +111,15 @@ class BluetoothLowEnergyEventRouter ...@@ -111,6 +111,15 @@ class BluetoothLowEnergyEventRouter
const base::Closure& callback, const base::Closure& callback,
const base::Closure& error_callback); const base::Closure& error_callback);
// Sends a request to write the value of the characteristic with instance ID
// |instance_id|, with value |value|. Returns false, if no such characteristic
// is known. Otherwise, returns true and invokes |callback| on success and
// |error_callback| on failure.
bool WriteCharacteristicValue(const std::string& instance_id,
const std::vector<uint8>& value,
const base::Closure& callback,
const base::Closure& error_callback);
// Initializes the adapter for testing. Used by unit tests only. // Initializes the adapter for testing. Used by unit tests only.
void SetAdapterForTesting(device::BluetoothAdapter* adapter); void SetAdapterForTesting(device::BluetoothAdapter* adapter);
......
{
"manifest_version": 2,
"name": "Test the Bluetooth Low Energy writeCharacteristicValue API",
"version": "1.0",
"app": {
"background": {
"scripts": ["runtest.js"]
}
},
"bluetooth": {}
}
// Copyright 2014 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.
function testWriteCharacteristicValue() {
chrome.test.assertTrue(characteristic != null, '\'characteristic\' is null');
chrome.test.assertEq(charId, characteristic.instanceId);
chrome.test.assertEq(writeValue.byteLength, characteristic.value.byteLength);
var receivedValueBytes = new Uint8Array(characteristic.value);
for (var i = 0; i < writeValue.byteLength; i++) {
chrome.test.assertEq(valueBytes[i], receivedValueBytes[i]);
}
chrome.test.succeed();
}
var writeCharacteristicValue =
chrome.bluetoothLowEnergy.writeCharacteristicValue;
var charId = 'char_id0';
var badCharId = 'char_id1';
var characteristic = null;
var bytes = [0x43, 0x68, 0x72, 0x6F, 0x6D, 0x65];
var writeValue = new ArrayBuffer(bytes.length);
var valueBytes = new Uint8Array(writeValue);
valueBytes.set(bytes);
// 1. Unknown characteristic instanceId.
writeCharacteristicValue(badCharId, writeValue, function (result) {
if (result || !chrome.runtime.lastError) {
chrome.test.fail('badCharId did not cause failure');
}
// 2. Known characteristic instanceId, but call failure.
writeCharacteristicValue(charId, writeValue, function (result) {
if (result || !chrome.runtime.lastError) {
chrome.test.fail('writeCharacteristicValue should have failed');
}
// 3. Call should succeed.
writeCharacteristicValue(charId, writeValue, function (result) {
if (chrome.runtime.lastError) {
chrome.test.fail(chrome.runtime.lastError.message);
}
chrome.bluetoothLowEnergy.getCharacteristic(charId, function (result) {
characteristic = result;
chrome.test.sendMessage('ready', function (message) {
chrome.test.runTests([testWriteCharacteristicValue]);
});
});
});
});
});
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