summaryrefslogtreecommitdiffstats
path: root/device
diff options
context:
space:
mode:
authortommyt <tommyt@opera.com>2016-03-14 15:12:28 -0700
committerCommit bot <commit-bot@chromium.org>2016-03-14 22:14:58 +0000
commit0348fa65c3d808f854f745fb9f8f185a5b74b922 (patch)
treea5dd2b2dc34bad55c18d974fb6d633ad13354493 /device
parent59d3539fc7ce60355ccf52c00733d33dde5e118a (diff)
downloadchromium_src-0348fa65c3d808f854f745fb9f8f185a5b74b922.zip
chromium_src-0348fa65c3d808f854f745fb9f8f185a5b74b922.tar.gz
chromium_src-0348fa65c3d808f854f745fb9f8f185a5b74b922.tar.bz2
bluetooth: android: Confirm the notify session after the descriptor has been written.
This change also implements WriteRemoteDescriptor and ReadRemoteDescriptor. Because of this, I've also added quite a few descriptor unit tests. These tests are pretty much the same as the read/write tests for characteristics. BUG=584369 Review URL: https://codereview.chromium.org/1712593002 Cr-Commit-Position: refs/heads/master@{#381088}
Diffstat (limited to 'device')
-rw-r--r--device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java38
-rw-r--r--device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java54
-rw-r--r--device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattDescriptor.java74
-rw-r--r--device/bluetooth/android/java/src/org/chromium/device/bluetooth/Wrappers.java36
-rw-r--r--device/bluetooth/bluetooth_gatt_characteristic.cc11
-rw-r--r--device/bluetooth/bluetooth_gatt_characteristic.h4
-rw-r--r--device/bluetooth/bluetooth_gatt_characteristic_unittest.cc7
-rw-r--r--device/bluetooth/bluetooth_gatt_descriptor_unittest.cc458
-rw-r--r--device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc75
-rw-r--r--device/bluetooth/bluetooth_remote_gatt_characteristic_android.h17
-rw-r--r--device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc102
-rw-r--r--device/bluetooth/bluetooth_remote_gatt_descriptor_android.h23
-rw-r--r--device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java72
-rw-r--r--device/bluetooth/test/bluetooth_test.cc1
-rw-r--r--device/bluetooth/test/bluetooth_test.h36
-rw-r--r--device/bluetooth/test/bluetooth_test_android.cc87
-rw-r--r--device/bluetooth/test/bluetooth_test_android.h24
17 files changed, 1015 insertions, 104 deletions
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
index 88e290f..b7fd6a1 100644
--- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
+++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
@@ -255,6 +255,44 @@ final class ChromeBluetoothDevice {
}
});
}
+
+ @Override
+ public void onDescriptorRead(
+ final Wrappers.BluetoothGattDescriptorWrapper descriptor, final int status) {
+ ThreadUtils.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ ChromeBluetoothRemoteGattDescriptor chromeDescriptor =
+ mWrapperToChromeDescriptorsMap.get(descriptor);
+ if (chromeDescriptor == null) {
+ // Android events arriving with no Chrome object is expected rarely: only
+ // when the event races object destruction.
+ Log.v(TAG, "onDescriptorRead when chromeDescriptor == null.");
+ } else {
+ chromeDescriptor.onDescriptorRead(status);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onDescriptorWrite(
+ final Wrappers.BluetoothGattDescriptorWrapper descriptor, final int status) {
+ ThreadUtils.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ ChromeBluetoothRemoteGattDescriptor chromeDescriptor =
+ mWrapperToChromeDescriptorsMap.get(descriptor);
+ if (chromeDescriptor == null) {
+ // Android events arriving with no Chrome object is expected rarely: only
+ // when the event races object destruction.
+ Log.v(TAG, "onDescriptorWrite when chromeDescriptor == null.");
+ } else {
+ chromeDescriptor.onDescriptorWrite(status);
+ }
+ }
+ });
+ }
}
// ---------------------------------------------------------------------------------------------
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java
index ea0a4dc..6d19c1f 100644
--- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java
+++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java
@@ -5,8 +5,6 @@
package org.chromium.device.bluetooth;
import android.annotation.TargetApi;
-import android.bluetooth.BluetoothGattCharacteristic;
-import android.bluetooth.BluetoothGattDescriptor;
import android.os.Build;
import org.chromium.base.Log;
@@ -14,7 +12,6 @@ import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import java.util.List;
-import java.util.UUID;
/**
* Exposes android.bluetooth.BluetoothGattCharacteristic as necessary
@@ -115,51 +112,6 @@ final class ChromeBluetoothRemoteGattCharacteristic {
return mCharacteristic.getProperties();
}
- // Implements BluetoothRemoteGattCharacteristicAndroid::StartNotifySession.
- @CalledByNative
- private boolean startNotifySession() {
- // Verify properties first, to provide clearest error log.
- int properties = mCharacteristic.getProperties();
- boolean hasNotify = (properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0;
- boolean hasIndicate = (properties & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0;
- if (!hasNotify && !hasIndicate) {
- Log.v(TAG, "startNotifySession failed! Characteristic needs NOTIFY or INDICATE.");
- return false;
- }
-
- // Find config descriptor.
- Wrappers.BluetoothGattDescriptorWrapper clientCharacteristicConfigurationDescriptor =
- mCharacteristic.getDescriptor(UUID.fromString(
- "00002902-0000-1000-8000-00805F9B34FB" /* Config's standard UUID*/));
- if (clientCharacteristicConfigurationDescriptor == null) {
- Log.v(TAG, "startNotifySession config descriptor failed!");
- return false;
- }
-
- // Request Android route onCharacteristicChanged notifications for this characteristic.
- if (!mChromeDevice.mBluetoothGatt.setCharacteristicNotification(mCharacteristic, true)) {
- Log.i(TAG, "startNotifySession setCharacteristicNotification failed.");
- return false;
- }
-
- // Enable notification on remote device's characteristic:
- if (!clientCharacteristicConfigurationDescriptor.setValue(hasNotify
- ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
- : BluetoothGattDescriptor.ENABLE_INDICATION_VALUE)) {
- Log.v(TAG, "startNotifySession descriptor setValue failed!");
- return false;
- }
- Log.v(TAG, hasNotify ? "startNotifySession NOTIFY." : "startNotifySession INDICATE.");
-
- if (!mChromeDevice.mBluetoothGatt.writeDescriptor(
- clientCharacteristicConfigurationDescriptor)) {
- Log.i(TAG, "startNotifySession writeDescriptor failed!");
- return false;
- }
-
- return true;
- }
-
// Implements BluetoothRemoteGattCharacteristicAndroid::ReadRemoteCharacteristic.
@CalledByNative
private boolean readRemoteCharacteristic() {
@@ -184,6 +136,12 @@ final class ChromeBluetoothRemoteGattCharacteristic {
return true;
}
+ // Enable or disable the notifications for this characteristic.
+ @CalledByNative
+ private boolean setCharacteristicNotification(boolean enabled) {
+ return mChromeDevice.mBluetoothGatt.setCharacteristicNotification(mCharacteristic, enabled);
+ }
+
// Creates objects for all descriptors. Designed only to be called by
// BluetoothRemoteGattCharacteristicAndroid::EnsureDescriptorsCreated.
@CalledByNative
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattDescriptor.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattDescriptor.java
index e87b57b..ac7489d 100644
--- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattDescriptor.java
+++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattDescriptor.java
@@ -18,19 +18,14 @@ import org.chromium.base.annotations.JNINamespace;
final class ChromeBluetoothRemoteGattDescriptor {
private static final String TAG = "Bluetooth";
- // TODO(scheib): Will need c++ pointer eventually:
- // private long mNativeBluetoothRemoteGattDescriptorAndroid;
+ private long mNativeBluetoothRemoteGattDescriptorAndroid;
final Wrappers.BluetoothGattDescriptorWrapper mDescriptor;
final ChromeBluetoothDevice mChromeDevice;
- private ChromeBluetoothRemoteGattDescriptor(
- // TODO(scheib): Will need c++ pointer eventually:
- // long nativeBluetoothRemoteGattDescriptorAndroid,
+ private ChromeBluetoothRemoteGattDescriptor(long nativeBluetoothRemoteGattDescriptorAndroid,
Wrappers.BluetoothGattDescriptorWrapper descriptorWrapper,
ChromeBluetoothDevice chromeDevice) {
- // TODO(scheib): Will need c++ pointer eventually:
- // mNativeBluetoothRemoteGattDescriptorAndroid =
- // nativeBluetoothRemoteGattDescriptorAndroid;
+ mNativeBluetoothRemoteGattDescriptorAndroid = nativeBluetoothRemoteGattDescriptorAndroid;
mDescriptor = descriptorWrapper;
mChromeDevice = chromeDevice;
@@ -45,11 +40,27 @@ final class ChromeBluetoothRemoteGattDescriptor {
@CalledByNative
private void onBluetoothRemoteGattDescriptorAndroidDestruction() {
Log.v(TAG, "ChromeBluetoothRemoteGattDescriptor Destroyed.");
- // TODO(scheib): Will need c++ pointer eventually:
- // mNativeBluetoothRemoteGattDescriptorAndroid = 0;
+ mNativeBluetoothRemoteGattDescriptorAndroid = 0;
mChromeDevice.mWrapperToChromeDescriptorsMap.remove(mDescriptor);
}
+ void onDescriptorRead(int status) {
+ Log.i(TAG, "onDescriptorRead status:%d==%s", status,
+ status == android.bluetooth.BluetoothGatt.GATT_SUCCESS ? "OK" : "Error");
+ if (mNativeBluetoothRemoteGattDescriptorAndroid != 0) {
+ nativeOnRead(
+ mNativeBluetoothRemoteGattDescriptorAndroid, status, mDescriptor.getValue());
+ }
+ }
+
+ void onDescriptorWrite(int status) {
+ Log.i(TAG, "onDescriptorWrite status:%d==%s", status,
+ status == android.bluetooth.BluetoothGatt.GATT_SUCCESS ? "OK" : "Error");
+ if (mNativeBluetoothRemoteGattDescriptorAndroid != 0) {
+ nativeOnWrite(mNativeBluetoothRemoteGattDescriptorAndroid, status);
+ }
+ }
+
// ---------------------------------------------------------------------------------------------
// BluetoothRemoteGattDescriptorAndroid methods implemented in java:
@@ -57,12 +68,9 @@ final class ChromeBluetoothRemoteGattDescriptor {
// TODO(http://crbug.com/505554): Replace 'Object' with specific type when JNI fixed.
@CalledByNative
private static ChromeBluetoothRemoteGattDescriptor create(
- // TODO(scheib): Will need c++ pointer eventually:
- // long nativeBluetoothRemoteGattDescriptorAndroid,
- Object bluetoothGattDescriptorWrapper, ChromeBluetoothDevice chromeDevice) {
- return new ChromeBluetoothRemoteGattDescriptor(
- // TODO(scheib): Will need c++ pointer eventually:
- // nativeBluetoothRemoteGattDescriptorAndroid,
+ long nativeBluetoothRemoteGattDescriptorAndroid, Object bluetoothGattDescriptorWrapper,
+ ChromeBluetoothDevice chromeDevice) {
+ return new ChromeBluetoothRemoteGattDescriptor(nativeBluetoothRemoteGattDescriptorAndroid,
(Wrappers.BluetoothGattDescriptorWrapper) bluetoothGattDescriptorWrapper,
chromeDevice);
}
@@ -72,4 +80,38 @@ final class ChromeBluetoothRemoteGattDescriptor {
private String getUUID() {
return mDescriptor.getUuid().toString();
}
+
+ // Implements BluetoothRemoteGattDescriptorAndroid::ReadRemoteDescriptor.
+ @CalledByNative
+ private boolean readRemoteDescriptor() {
+ if (!mChromeDevice.mBluetoothGatt.readDescriptor(mDescriptor)) {
+ Log.i(TAG, "readRemoteDescriptor readDescriptor failed.");
+ return false;
+ }
+ return true;
+ }
+
+ // Implements BluetoothRemoteGattDescriptorAndroid::WriteRemoteDescriptor.
+ @CalledByNative
+ private boolean writeRemoteDescriptor(byte[] value) {
+ if (!mDescriptor.setValue(value)) {
+ Log.i(TAG, "writeRemoteDescriptor setValue failed.");
+ return false;
+ }
+ if (!mChromeDevice.mBluetoothGatt.writeDescriptor(mDescriptor)) {
+ Log.i(TAG, "writeRemoteDescriptor writeDescriptor failed.");
+ return false;
+ }
+ return true;
+ }
+
+ // ---------------------------------------------------------------------------------------------
+ // BluetoothAdapterDevice C++ methods declared for access from java:
+
+ // Binds to BluetoothRemoteGattDescriptorAndroid::OnRead.
+ native void nativeOnRead(
+ long nativeBluetoothRemoteGattDescriptorAndroid, int status, byte[] value);
+
+ // Binds to BluetoothRemoteGattDescriptorAndroid::OnWrite.
+ native void nativeOnWrite(long nativeBluetoothRemoteGattDescriptorAndroid, int status);
}
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/Wrappers.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/Wrappers.java
index 96634b3..b61c7cd 100644
--- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/Wrappers.java
+++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/Wrappers.java
@@ -365,6 +365,10 @@ class Wrappers {
return mGatt.writeCharacteristic(characteristic.mCharacteristic);
}
+ boolean readDescriptor(BluetoothGattDescriptorWrapper descriptor) {
+ return mGatt.readDescriptor(descriptor.mDescriptor);
+ }
+
boolean writeDescriptor(BluetoothGattDescriptorWrapper descriptor) {
return mGatt.writeDescriptor(descriptor.mDescriptor);
}
@@ -411,6 +415,20 @@ class Wrappers {
}
@Override
+ public void onDescriptorRead(
+ BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
+ mWrapperCallback.onDescriptorRead(
+ mDeviceWrapper.mDescriptorsToWrappers.get(descriptor), status);
+ }
+
+ @Override
+ public void onDescriptorWrite(
+ BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
+ mWrapperCallback.onDescriptorWrite(
+ mDeviceWrapper.mDescriptorsToWrappers.get(descriptor), status);
+ }
+
+ @Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
mWrapperCallback.onConnectionStateChange(status, newState);
}
@@ -438,6 +456,10 @@ class Wrappers {
BluetoothGattCharacteristicWrapper characteristic, int status);
public abstract void onCharacteristicWrite(
BluetoothGattCharacteristicWrapper characteristic, int status);
+ public abstract void onDescriptorRead(
+ BluetoothGattDescriptorWrapper descriptor, int status);
+ public abstract void onDescriptorWrite(
+ BluetoothGattDescriptorWrapper descriptor, int status);
public abstract void onConnectionStateChange(int status, int newState);
public abstract void onServicesDiscovered(int status);
}
@@ -505,7 +527,7 @@ class Wrappers {
mDeviceWrapper.mDescriptorsToWrappers.get(descriptor);
if (descriptorWrapper == null) {
- descriptorWrapper = new BluetoothGattDescriptorWrapper(descriptor);
+ descriptorWrapper = new BluetoothGattDescriptorWrapper(descriptor, mDeviceWrapper);
mDeviceWrapper.mDescriptorsToWrappers.put(descriptor, descriptorWrapper);
}
return descriptorWrapper;
@@ -521,7 +543,8 @@ class Wrappers {
BluetoothGattDescriptorWrapper descriptorWrapper =
mDeviceWrapper.mDescriptorsToWrappers.get(descriptor);
if (descriptorWrapper == null) {
- descriptorWrapper = new BluetoothGattDescriptorWrapper(descriptor);
+ descriptorWrapper =
+ new BluetoothGattDescriptorWrapper(descriptor, mDeviceWrapper);
mDeviceWrapper.mDescriptorsToWrappers.put(descriptor, descriptorWrapper);
}
descriptorsWrapped.add(descriptorWrapper);
@@ -555,9 +578,16 @@ class Wrappers {
*/
static class BluetoothGattDescriptorWrapper {
private final BluetoothGattDescriptor mDescriptor;
+ final BluetoothDeviceWrapper mDeviceWrapper;
- public BluetoothGattDescriptorWrapper(BluetoothGattDescriptor descriptor) {
+ public BluetoothGattDescriptorWrapper(
+ BluetoothGattDescriptor descriptor, BluetoothDeviceWrapper deviceWrapper) {
mDescriptor = descriptor;
+ mDeviceWrapper = deviceWrapper;
+ }
+
+ public BluetoothGattCharacteristicWrapper getCharacteristic() {
+ return mDeviceWrapper.mCharacteristicsToWrappers.get(mDescriptor.getCharacteristic());
}
public UUID getUuid() {
diff --git a/device/bluetooth/bluetooth_gatt_characteristic.cc b/device/bluetooth/bluetooth_gatt_characteristic.cc
index f7bb6d8..66c39f6 100644
--- a/device/bluetooth/bluetooth_gatt_characteristic.cc
+++ b/device/bluetooth/bluetooth_gatt_characteristic.cc
@@ -5,6 +5,7 @@
#include "device/bluetooth/bluetooth_gatt_characteristic.h"
#include "base/logging.h"
+#include "device/bluetooth/bluetooth_gatt_descriptor.h"
namespace device {
@@ -24,4 +25,14 @@ BluetoothGattCharacteristic* BluetoothGattCharacteristic::Create(
return NULL;
}
+BluetoothGattDescriptor* BluetoothGattCharacteristic::GetDescriptorForUUID(
+ const BluetoothUUID& uuid) {
+ for (BluetoothGattDescriptor* descriptor : GetDescriptors()) {
+ if (descriptor->GetUUID() == uuid) {
+ return descriptor;
+ }
+ }
+ return NULL;
+}
+
} // namespace device
diff --git a/device/bluetooth/bluetooth_gatt_characteristic.h b/device/bluetooth/bluetooth_gatt_characteristic.h
index 8cce601..2eeeeff 100644
--- a/device/bluetooth/bluetooth_gatt_characteristic.h
+++ b/device/bluetooth/bluetooth_gatt_characteristic.h
@@ -158,6 +158,10 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothGattCharacteristic {
virtual BluetoothGattDescriptor* GetDescriptor(
const std::string& identifier) const = 0;
+ // Returns the GATT characteristic descriptor that matches |uuid|.
+ virtual BluetoothGattDescriptor* GetDescriptorForUUID(
+ const BluetoothUUID& uuid);
+
// Adds a characteristic descriptor to the locally hosted characteristic
// represented by this instance. This method only makes sense for local
// characteristics and won't have an effect if this instance represents a
diff --git a/device/bluetooth/bluetooth_gatt_characteristic_unittest.cc b/device/bluetooth/bluetooth_gatt_characteristic_unittest.cc
index d320f95..ba3e25b 100644
--- a/device/bluetooth/bluetooth_gatt_characteristic_unittest.cc
+++ b/device/bluetooth/bluetooth_gatt_characteristic_unittest.cc
@@ -907,14 +907,7 @@ TEST_F(BluetoothGattCharacteristicTest, StartNotifySession_Multiple) {
characteristic1_->StartNotifySession(
GetNotifyCallback(Call::EXPECTED),
GetGattErrorCallback(Call::NOT_EXPECTED));
-#if defined(OS_ANDROID)
- // TODO(crbug.com/551634): Decide when implementing IsNotifying if Android
- // should trust the notification request always worked, or if we should always
- // redundantly set the value to the OS.
- EXPECT_EQ(2, gatt_notify_characteristic_attempts_);
-#else
EXPECT_EQ(1, gatt_notify_characteristic_attempts_);
-#endif
EXPECT_EQ(0, callback_count_);
SimulateGattNotifySessionStarted(characteristic1_);
EXPECT_EQ(2, callback_count_);
diff --git a/device/bluetooth/bluetooth_gatt_descriptor_unittest.cc b/device/bluetooth/bluetooth_gatt_descriptor_unittest.cc
index a2c0bd9..190de7d 100644
--- a/device/bluetooth/bluetooth_gatt_descriptor_unittest.cc
+++ b/device/bluetooth/bluetooth_gatt_descriptor_unittest.cc
@@ -16,7 +16,42 @@
namespace device {
#if defined(OS_ANDROID) || defined(OS_MACOSX)
-class BluetoothGattDescriptorTest : public BluetoothTest {};
+class BluetoothGattDescriptorTest : public BluetoothTest {
+ public:
+ // Creates adapter_, device_, service_, characteristic_,
+ // descriptor1_, & descriptor2_.
+ void FakeDescriptorBoilerplate() {
+ InitWithFakeAdapter();
+ StartLowEnergyDiscoverySession();
+ device_ = DiscoverLowEnergyDevice(3);
+ device_->CreateGattConnection(GetGattConnectionCallback(Call::EXPECTED),
+ GetConnectErrorCallback(Call::NOT_EXPECTED));
+ SimulateGattConnection(device_);
+ std::vector<std::string> services;
+ std::string uuid("00000000-0000-1000-8000-00805f9b34fb");
+ services.push_back(uuid);
+ SimulateGattServicesDiscovered(device_, services);
+ ASSERT_EQ(1u, device_->GetGattServices().size());
+ service_ = device_->GetGattServices()[0];
+ SimulateGattCharacteristic(service_, uuid, 0);
+ ASSERT_EQ(1u, service_->GetCharacteristics().size());
+ characteristic_ = service_->GetCharacteristics()[0];
+ SimulateGattDescriptor(characteristic_,
+ "00000001-0000-1000-8000-00805f9b34fb");
+ SimulateGattDescriptor(characteristic_,
+ "00000002-0000-1000-8000-00805f9b34fb");
+ ASSERT_EQ(2u, characteristic_->GetDescriptors().size());
+ descriptor1_ = characteristic_->GetDescriptors()[0];
+ descriptor2_ = characteristic_->GetDescriptors()[1];
+ ResetEventCounts();
+ }
+
+ BluetoothDevice* device_ = nullptr;
+ BluetoothGattService* service_ = nullptr;
+ BluetoothGattCharacteristic* characteristic_ = nullptr;
+ BluetoothGattDescriptor* descriptor1_ = nullptr;
+ BluetoothGattDescriptor* descriptor2_ = nullptr;
+};
#endif
#if defined(OS_ANDROID)
@@ -137,4 +172,425 @@ TEST_F(BluetoothGattDescriptorTest, GetUUID) {
}
#endif // defined(OS_ANDROID)
+#if defined(OS_ANDROID)
+// Tests ReadRemoteDescriptor and GetValue with empty value buffer.
+TEST_F(BluetoothGattDescriptorTest, ReadRemoteDescriptor_Empty) {
+ ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());
+
+ descriptor1_->ReadRemoteDescriptor(GetReadValueCallback(Call::EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+ EXPECT_EQ(1, gatt_read_descriptor_attempts_);
+ std::vector<uint8_t> empty_vector;
+ SimulateGattDescriptorRead(descriptor1_, empty_vector);
+
+ // Duplicate read reported from OS shouldn't cause a problem:
+ SimulateGattDescriptorRead(descriptor1_, empty_vector);
+
+ EXPECT_EQ(empty_vector, last_read_value_);
+ EXPECT_EQ(empty_vector, descriptor1_->GetValue());
+}
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// Tests WriteRemoteDescriptor with empty value buffer.
+TEST_F(BluetoothGattDescriptorTest, WriteRemoteDescriptor_Empty) {
+ ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());
+
+ std::vector<uint8_t> empty_vector;
+ descriptor1_->WriteRemoteDescriptor(empty_vector, GetCallback(Call::EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+ EXPECT_EQ(1, gatt_write_descriptor_attempts_);
+ SimulateGattDescriptorWrite(descriptor1_);
+
+ EXPECT_EQ(empty_vector, last_write_value_);
+}
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// Tests ReadRemoteDescriptor completing after Chrome objects are deleted.
+TEST_F(BluetoothGattDescriptorTest, ReadRemoteDescriptor_AfterDeleted) {
+ ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());
+
+ descriptor1_->ReadRemoteDescriptor(GetReadValueCallback(Call::NOT_EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+
+ RememberDescriptorForSubsequentAction(descriptor1_);
+ DeleteDevice(device_);
+
+ std::vector<uint8_t> empty_vector;
+ SimulateGattDescriptorRead(/* use remembered descriptor */ nullptr,
+ empty_vector);
+ EXPECT_TRUE("Did not crash!");
+}
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// Tests WriteRemoteDescriptor completing after Chrome objects are deleted.
+TEST_F(BluetoothGattDescriptorTest, WriteRemoteDescriptor_AfterDeleted) {
+ ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());
+
+ std::vector<uint8_t> empty_vector;
+ descriptor1_->WriteRemoteDescriptor(empty_vector,
+ GetCallback(Call::NOT_EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+
+ RememberDescriptorForSubsequentAction(descriptor1_);
+ DeleteDevice(device_);
+
+ SimulateGattDescriptorWrite(/* use remembered descriptor */ nullptr);
+ EXPECT_TRUE("Did not crash!");
+}
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// Tests ReadRemoteDescriptor and GetValue with non-empty value buffer.
+TEST_F(BluetoothGattDescriptorTest, ReadRemoteDescriptor) {
+ ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());
+
+ descriptor1_->ReadRemoteDescriptor(GetReadValueCallback(Call::EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+ EXPECT_EQ(1, gatt_read_descriptor_attempts_);
+
+ uint8_t values[] = {0, 1, 2, 3, 4, 0xf, 0xf0, 0xff};
+ std::vector<uint8_t> test_vector(values, values + arraysize(values));
+ SimulateGattDescriptorRead(descriptor1_, test_vector);
+
+ // Duplicate read reported from OS shouldn't cause a problem:
+ std::vector<uint8_t> empty_vector;
+ SimulateGattDescriptorRead(descriptor1_, empty_vector);
+
+ EXPECT_EQ(test_vector, last_read_value_);
+ EXPECT_EQ(test_vector, descriptor1_->GetValue());
+}
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// Tests WriteRemoteDescriptor with non-empty value buffer.
+TEST_F(BluetoothGattDescriptorTest, WriteRemoteDescriptor) {
+ ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());
+
+ uint8_t values[] = {0, 1, 2, 3, 4, 0xf, 0xf0, 0xff};
+ std::vector<uint8_t> test_vector(values, values + arraysize(values));
+ descriptor1_->WriteRemoteDescriptor(test_vector, GetCallback(Call::EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+ EXPECT_EQ(1, gatt_write_descriptor_attempts_);
+
+ SimulateGattDescriptorWrite(descriptor1_);
+
+ EXPECT_EQ(test_vector, last_write_value_);
+}
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// Tests ReadRemoteDescriptor and GetValue multiple times.
+TEST_F(BluetoothGattDescriptorTest, ReadRemoteDescriptor_Twice) {
+ ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());
+
+ descriptor1_->ReadRemoteDescriptor(GetReadValueCallback(Call::EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+ EXPECT_EQ(1, gatt_read_descriptor_attempts_);
+
+ uint8_t values[] = {0, 1, 2, 3, 4, 0xf, 0xf0, 0xff};
+ std::vector<uint8_t> test_vector(values, values + arraysize(values));
+ SimulateGattDescriptorRead(descriptor1_, test_vector);
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_EQ(test_vector, last_read_value_);
+ EXPECT_EQ(test_vector, descriptor1_->GetValue());
+
+ // Read again, with different value:
+ ResetEventCounts();
+ descriptor1_->ReadRemoteDescriptor(GetReadValueCallback(Call::EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+ EXPECT_EQ(1, gatt_read_descriptor_attempts_);
+ std::vector<uint8_t> empty_vector;
+ SimulateGattDescriptorRead(descriptor1_, empty_vector);
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_EQ(empty_vector, last_read_value_);
+ EXPECT_EQ(empty_vector, descriptor1_->GetValue());
+}
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// Tests WriteRemoteDescriptor multiple times.
+TEST_F(BluetoothGattDescriptorTest, WriteRemoteDescriptor_Twice) {
+ ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());
+
+ uint8_t values[] = {0, 1, 2, 3, 4, 0xf, 0xf0, 0xff};
+ std::vector<uint8_t> test_vector(values, values + arraysize(values));
+ descriptor1_->WriteRemoteDescriptor(test_vector, GetCallback(Call::EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+ EXPECT_EQ(1, gatt_write_descriptor_attempts_);
+
+ SimulateGattDescriptorWrite(descriptor1_);
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_EQ(test_vector, last_write_value_);
+
+ // Write again, with different value:
+ ResetEventCounts();
+ std::vector<uint8_t> empty_vector;
+ descriptor1_->WriteRemoteDescriptor(empty_vector, GetCallback(Call::EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+ EXPECT_EQ(1, gatt_write_descriptor_attempts_);
+ SimulateGattDescriptorWrite(descriptor1_);
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_EQ(empty_vector, last_write_value_);
+}
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// Tests ReadRemoteDescriptor on two descriptors.
+TEST_F(BluetoothGattDescriptorTest, ReadRemoteDescriptor_MultipleDescriptors) {
+ ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());
+
+ descriptor1_->ReadRemoteDescriptor(GetReadValueCallback(Call::EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+ descriptor2_->ReadRemoteDescriptor(GetReadValueCallback(Call::EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+ EXPECT_EQ(2, gatt_read_descriptor_attempts_);
+ EXPECT_EQ(0, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+
+ std::vector<uint8_t> test_vector1;
+ test_vector1.push_back(111);
+ SimulateGattDescriptorRead(descriptor1_, test_vector1);
+ EXPECT_EQ(test_vector1, last_read_value_);
+
+ std::vector<uint8_t> test_vector2;
+ test_vector2.push_back(222);
+ SimulateGattDescriptorRead(descriptor2_, test_vector2);
+ EXPECT_EQ(test_vector2, last_read_value_);
+
+ EXPECT_EQ(2, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_EQ(test_vector1, descriptor1_->GetValue());
+ EXPECT_EQ(test_vector2, descriptor2_->GetValue());
+}
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// Tests WriteRemoteDescriptor on two descriptors.
+TEST_F(BluetoothGattDescriptorTest, WriteRemoteDescriptor_MultipleDescriptors) {
+ ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());
+
+ std::vector<uint8_t> test_vector1;
+ test_vector1.push_back(111);
+ descriptor1_->WriteRemoteDescriptor(test_vector1, GetCallback(Call::EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+ EXPECT_EQ(test_vector1, last_write_value_);
+
+ std::vector<uint8_t> test_vector2;
+ test_vector2.push_back(222);
+ descriptor2_->WriteRemoteDescriptor(test_vector2, GetCallback(Call::EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+ EXPECT_EQ(test_vector2, last_write_value_);
+
+ EXPECT_EQ(2, gatt_write_descriptor_attempts_);
+ EXPECT_EQ(0, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+
+ SimulateGattDescriptorWrite(descriptor1_);
+ SimulateGattDescriptorWrite(descriptor2_);
+
+ EXPECT_EQ(2, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+}
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// Tests ReadRemoteDescriptor asynchronous error.
+TEST_F(BluetoothGattDescriptorTest, ReadError) {
+ ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());
+
+ descriptor1_->ReadRemoteDescriptor(GetReadValueCallback(Call::NOT_EXPECTED),
+ GetGattErrorCallback(Call::EXPECTED));
+ SimulateGattDescriptorReadError(
+ descriptor1_, BluetoothGattService::GATT_ERROR_INVALID_LENGTH);
+ SimulateGattDescriptorReadError(descriptor1_,
+ BluetoothGattService::GATT_ERROR_FAILED);
+ EXPECT_EQ(BluetoothGattService::GATT_ERROR_INVALID_LENGTH,
+ last_gatt_error_code_);
+}
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// Tests WriteRemoteDescriptor asynchronous error.
+TEST_F(BluetoothGattDescriptorTest, WriteError) {
+ ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());
+
+ std::vector<uint8_t> empty_vector;
+ descriptor1_->WriteRemoteDescriptor(empty_vector,
+ GetCallback(Call::NOT_EXPECTED),
+ GetGattErrorCallback(Call::EXPECTED));
+ SimulateGattDescriptorWriteError(
+ descriptor1_, BluetoothGattService::GATT_ERROR_INVALID_LENGTH);
+ SimulateGattDescriptorWriteError(descriptor1_,
+ BluetoothGattService::GATT_ERROR_FAILED);
+
+ EXPECT_EQ(BluetoothGattService::GATT_ERROR_INVALID_LENGTH,
+ last_gatt_error_code_);
+}
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// Tests ReadRemoteDescriptor synchronous error.
+TEST_F(BluetoothGattDescriptorTest, ReadSynchronousError) {
+ ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());
+
+ SimulateGattDescriptorReadWillFailSynchronouslyOnce(descriptor1_);
+ descriptor1_->ReadRemoteDescriptor(GetReadValueCallback(Call::NOT_EXPECTED),
+ GetGattErrorCallback(Call::EXPECTED));
+ EXPECT_EQ(0, gatt_read_descriptor_attempts_);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0, callback_count_);
+ EXPECT_EQ(1, error_callback_count_);
+ EXPECT_EQ(BluetoothGattService::GATT_ERROR_FAILED, last_gatt_error_code_);
+
+ // After failing once, can succeed:
+ ResetEventCounts();
+ descriptor1_->ReadRemoteDescriptor(GetReadValueCallback(Call::EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+ EXPECT_EQ(1, gatt_read_descriptor_attempts_);
+ std::vector<uint8_t> empty_vector;
+ SimulateGattDescriptorRead(descriptor1_, empty_vector);
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+}
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// Tests WriteRemoteDescriptor synchronous error.
+TEST_F(BluetoothGattDescriptorTest, WriteSynchronousError) {
+ ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());
+
+ SimulateGattDescriptorWriteWillFailSynchronouslyOnce(descriptor1_);
+ std::vector<uint8_t> empty_vector;
+ descriptor1_->WriteRemoteDescriptor(empty_vector,
+ GetCallback(Call::NOT_EXPECTED),
+ GetGattErrorCallback(Call::EXPECTED));
+ EXPECT_EQ(0, gatt_write_descriptor_attempts_);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0, callback_count_);
+ EXPECT_EQ(1, error_callback_count_);
+ EXPECT_EQ(BluetoothGattService::GATT_ERROR_FAILED, last_gatt_error_code_);
+
+ // After failing once, can succeed:
+ ResetEventCounts();
+ descriptor1_->WriteRemoteDescriptor(empty_vector, GetCallback(Call::EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+ EXPECT_EQ(1, gatt_write_descriptor_attempts_);
+ SimulateGattDescriptorWrite(descriptor1_);
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+}
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// Tests ReadRemoteDescriptor error with a pending read operation.
+TEST_F(BluetoothGattDescriptorTest, ReadRemoteDescriptor_ReadPending) {
+ ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());
+
+ descriptor1_->ReadRemoteDescriptor(GetReadValueCallback(Call::EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+ descriptor1_->ReadRemoteDescriptor(GetReadValueCallback(Call::NOT_EXPECTED),
+ GetGattErrorCallback(Call::EXPECTED));
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(0, callback_count_);
+ EXPECT_EQ(1, error_callback_count_);
+ EXPECT_EQ(BluetoothGattService::GATT_ERROR_IN_PROGRESS,
+ last_gatt_error_code_);
+
+ // Initial read should still succeed:
+ ResetEventCounts();
+ std::vector<uint8_t> empty_vector;
+ SimulateGattDescriptorRead(descriptor1_, empty_vector);
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+}
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// Tests WriteRemoteDescriptor error with a pending write operation.
+TEST_F(BluetoothGattDescriptorTest, WriteRemoteDescriptor_WritePending) {
+ ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());
+
+ std::vector<uint8_t> empty_vector;
+ descriptor1_->WriteRemoteDescriptor(empty_vector, GetCallback(Call::EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+ descriptor1_->WriteRemoteDescriptor(empty_vector,
+ GetCallback(Call::NOT_EXPECTED),
+ GetGattErrorCallback(Call::EXPECTED));
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(0, callback_count_);
+ EXPECT_EQ(1, error_callback_count_);
+ EXPECT_EQ(BluetoothGattService::GATT_ERROR_IN_PROGRESS,
+ last_gatt_error_code_);
+
+ // Initial write should still succeed:
+ ResetEventCounts();
+ SimulateGattDescriptorWrite(descriptor1_);
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+}
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// Tests ReadRemoteDescriptor error with a pending write operation.
+TEST_F(BluetoothGattDescriptorTest, ReadRemoteDescriptor_WritePending) {
+ ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());
+
+ std::vector<uint8_t> empty_vector;
+ descriptor1_->WriteRemoteDescriptor(empty_vector, GetCallback(Call::EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+ descriptor1_->ReadRemoteDescriptor(GetReadValueCallback(Call::NOT_EXPECTED),
+ GetGattErrorCallback(Call::EXPECTED));
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(0, callback_count_);
+ EXPECT_EQ(1, error_callback_count_);
+ EXPECT_EQ(BluetoothGattService::GATT_ERROR_IN_PROGRESS,
+ last_gatt_error_code_);
+
+ // Initial write should still succeed:
+ ResetEventCounts();
+ SimulateGattDescriptorWrite(descriptor1_);
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+}
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// Tests WriteRemoteDescriptor error with a pending Read operation.
+TEST_F(BluetoothGattDescriptorTest, WriteRemoteDescriptor_ReadPending) {
+ ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());
+
+ std::vector<uint8_t> empty_vector;
+ descriptor1_->ReadRemoteDescriptor(GetReadValueCallback(Call::EXPECTED),
+ GetGattErrorCallback(Call::NOT_EXPECTED));
+ descriptor1_->WriteRemoteDescriptor(empty_vector,
+ GetCallback(Call::NOT_EXPECTED),
+ GetGattErrorCallback(Call::EXPECTED));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(0, callback_count_);
+ EXPECT_EQ(1, error_callback_count_);
+ EXPECT_EQ(BluetoothGattService::GATT_ERROR_IN_PROGRESS,
+ last_gatt_error_code_);
+
+ // Initial read should still succeed:
+ ResetEventCounts();
+ SimulateGattDescriptorRead(descriptor1_, empty_vector);
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+}
+#endif // defined(OS_ANDROID)
+
} // namespace device
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc
index d8d0299..bb7e669 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc
@@ -136,20 +136,60 @@ bool BluetoothRemoteGattCharacteristicAndroid::UpdateValue(
void BluetoothRemoteGattCharacteristicAndroid::StartNotifySession(
const NotifySessionCallback& callback,
const ErrorCallback& error_callback) {
- if (Java_ChromeBluetoothRemoteGattCharacteristic_startNotifySession(
- AttachCurrentThread(), j_characteristic_.obj())) {
- // TODO(crbug.com/569664): Wait until descriptor write completes before
- // reporting success via calling |callback|.
- scoped_ptr<device::BluetoothGattNotifySession> notify_session(
- new BluetoothGattNotifySessionAndroid(instance_id_));
+ if (!pending_start_notify_calls_.empty()) {
+ pending_start_notify_calls_.push(std::make_pair(callback, error_callback));
+ return;
+ }
+
+ Properties properties = GetProperties();
+
+ bool hasNotify = properties & PROPERTY_NOTIFY;
+ bool hasIndicate = properties & PROPERTY_INDICATE;
+
+ if (!hasNotify && !hasIndicate) {
+ LOG(ERROR) << "Characteristic needs NOTIFY or INDICATE";
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(error_callback,
+ BluetoothRemoteGattServiceAndroid::GATT_ERROR_FAILED));
+ return;
+ }
+
+ BluetoothGattDescriptor* descriptor = GetDescriptorForUUID(
+ BluetoothGattDescriptor::ClientCharacteristicConfigurationUuid());
+
+ if (!descriptor) {
+ LOG(ERROR)
+ << "Could not find client characteristic configuration descriptor";
base::MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(callback, base::Passed(&notify_session)));
- } else {
+ FROM_HERE,
+ base::Bind(error_callback,
+ BluetoothRemoteGattServiceAndroid::GATT_ERROR_FAILED));
+ return;
+ }
+
+ if (!Java_ChromeBluetoothRemoteGattCharacteristic_setCharacteristicNotification(
+ AttachCurrentThread(), j_characteristic_.obj(), true)) {
+ LOG(ERROR) << "Error enabling characteristic notification";
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(error_callback,
BluetoothRemoteGattServiceAndroid::GATT_ERROR_FAILED));
+ return;
}
+
+ std::vector<uint8_t> value;
+ value.push_back(hasNotify ? 1 : 2);
+ value.push_back(0);
+
+ pending_start_notify_calls_.push(std::make_pair(callback, error_callback));
+ descriptor->WriteRemoteDescriptor(
+ value, base::Bind(&BluetoothRemoteGattCharacteristicAndroid::
+ OnStartNotifySessionSuccess,
+ base::Unretained(this)),
+ base::Bind(
+ &BluetoothRemoteGattCharacteristicAndroid::OnStartNotifySessionError,
+ base::Unretained(this)));
}
void BluetoothRemoteGattCharacteristicAndroid::ReadRemoteCharacteristic(
@@ -211,6 +251,25 @@ void BluetoothRemoteGattCharacteristicAndroid::OnChanged(
adapter_->NotifyGattCharacteristicValueChanged(this, value_);
}
+void BluetoothRemoteGattCharacteristicAndroid::OnStartNotifySessionSuccess() {
+ while (!pending_start_notify_calls_.empty()) {
+ PendingStartNotifyCall callbacks = pending_start_notify_calls_.front();
+ pending_start_notify_calls_.pop();
+ scoped_ptr<device::BluetoothGattNotifySession> notify_session(
+ new BluetoothGattNotifySessionAndroid(instance_id_));
+ callbacks.first.Run(std::move(notify_session));
+ }
+}
+
+void BluetoothRemoteGattCharacteristicAndroid::OnStartNotifySessionError(
+ BluetoothGattService::GattErrorCode error) {
+ while (!pending_start_notify_calls_.empty()) {
+ PendingStartNotifyCall callbacks = pending_start_notify_calls_.front();
+ pending_start_notify_calls_.pop();
+ callbacks.second.Run(error);
+ }
+}
+
void BluetoothRemoteGattCharacteristicAndroid::OnRead(
JNIEnv* env,
const JavaParamRef<jobject>& jcaller,
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_android.h b/device/bluetooth/bluetooth_remote_gatt_characteristic_android.h
index 4493a94..606b7d4 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_android.h
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_android.h
@@ -7,6 +7,8 @@
#include <stdint.h>
+#include <queue>
+
#include "base/android/jni_android.h"
#include "base/containers/scoped_ptr_hash_map.h"
#include "base/macros.h"
@@ -73,18 +75,24 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristicAndroid
const base::Closure& callback,
const ErrorCallback& error_callback) override;
+ // Called when StartNotifySession operation succeeds.
+ void OnStartNotifySessionSuccess();
+
+ // Called when StartNotifySession operation fails.
+ void OnStartNotifySessionError(BluetoothGattService::GattErrorCode error);
+
// Called when value changed event occurs.
void OnChanged(JNIEnv* env,
const base::android::JavaParamRef<jobject>& jcaller,
const base::android::JavaParamRef<jbyteArray>& value);
- // Callback after Read operation completes.
+ // Called when Read operation completes.
void OnRead(JNIEnv* env,
const base::android::JavaParamRef<jobject>& jcaller,
int32_t status,
const base::android::JavaParamRef<jbyteArray>& value);
- // Callback after Write operation completes.
+ // Called when Write operation completes.
void OnWrite(JNIEnv* env,
const base::android::JavaParamRef<jobject>& jcaller,
int32_t status);
@@ -123,6 +131,11 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristicAndroid
// Adapter unique instance ID.
std::string instance_id_;
+ // StartNotifySession callbacks and pending state.
+ typedef std::pair<NotifySessionCallback, ErrorCallback>
+ PendingStartNotifyCall;
+ std::queue<PendingStartNotifyCall> pending_start_notify_calls_;
+
// ReadRemoteCharacteristic callbacks and pending state.
bool read_pending_ = false;
ValueCallback read_callback_;
diff --git a/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc b/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc
index d197a78..39b812f 100644
--- a/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc
@@ -31,9 +31,7 @@ BluetoothRemoteGattDescriptorAndroid::Create(
descriptor->j_descriptor_.Reset(
Java_ChromeBluetoothRemoteGattDescriptor_create(
- AttachCurrentThread(),
- // TODO(scheib) Will eventually need to pass c++ pointer:
- // reinterpret_cast<intptr_t>(descriptor.get()),
+ AttachCurrentThread(), reinterpret_cast<intptr_t>(descriptor.get()),
bluetooth_gatt_descriptor_wrapper, chrome_bluetooth_device));
return descriptor;
@@ -71,9 +69,7 @@ bool BluetoothRemoteGattDescriptorAndroid::IsLocal() const {
const std::vector<uint8_t>& BluetoothRemoteGattDescriptorAndroid::GetValue()
const {
- NOTIMPLEMENTED();
- static std::vector<uint8_t> empty_value;
- return empty_value;
+ return value_;
}
BluetoothGattCharacteristic*
@@ -91,20 +87,98 @@ BluetoothRemoteGattDescriptorAndroid::GetPermissions() const {
void BluetoothRemoteGattDescriptorAndroid::ReadRemoteDescriptor(
const ValueCallback& callback,
const ErrorCallback& error_callback) {
- NOTIMPLEMENTED();
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(error_callback, BluetoothGattService::GATT_ERROR_FAILED));
+ if (read_pending_ || write_pending_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(error_callback,
+ BluetoothGattService::GATT_ERROR_IN_PROGRESS));
+ return;
+ }
+
+ if (!Java_ChromeBluetoothRemoteGattDescriptor_readRemoteDescriptor(
+ AttachCurrentThread(), j_descriptor_.obj())) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(error_callback,
+ BluetoothRemoteGattServiceAndroid::GATT_ERROR_FAILED));
+ return;
+ }
+
+ read_pending_ = true;
+ read_callback_ = callback;
+ read_error_callback_ = error_callback;
}
void BluetoothRemoteGattDescriptorAndroid::WriteRemoteDescriptor(
const std::vector<uint8_t>& new_value,
const base::Closure& callback,
const ErrorCallback& error_callback) {
- NOTIMPLEMENTED();
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(error_callback, BluetoothGattService::GATT_ERROR_FAILED));
+ if (read_pending_ || write_pending_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(error_callback,
+ BluetoothGattService::GATT_ERROR_IN_PROGRESS));
+ return;
+ }
+
+ JNIEnv* env = AttachCurrentThread();
+ if (!Java_ChromeBluetoothRemoteGattDescriptor_writeRemoteDescriptor(
+ env, j_descriptor_.obj(),
+ base::android::ToJavaByteArray(env, new_value).obj())) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(error_callback,
+ BluetoothRemoteGattServiceAndroid::GATT_ERROR_FAILED));
+ return;
+ }
+
+ write_pending_ = true;
+ write_callback_ = callback;
+ write_error_callback_ = error_callback;
+}
+
+void BluetoothRemoteGattDescriptorAndroid::OnRead(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& jcaller,
+ int32_t status,
+ const JavaParamRef<jbyteArray>& value) {
+ read_pending_ = false;
+
+ // Clear callbacks before calling to avoid reentrancy issues.
+ ValueCallback read_callback = read_callback_;
+ ErrorCallback read_error_callback = read_error_callback_;
+ read_callback_.Reset();
+ read_error_callback_.Reset();
+
+ if (status == 0 // android.bluetooth.BluetoothGatt.GATT_SUCCESS
+ && !read_callback.is_null()) {
+ base::android::JavaByteArrayToByteVector(env, value, &value_);
+ read_callback.Run(value_);
+ // TODO(https://crbug.com/584369): Call GattDescriptorValueChanged.
+ } else if (!read_error_callback.is_null()) {
+ read_error_callback.Run(
+ BluetoothRemoteGattServiceAndroid::GetGattErrorCode(status));
+ }
+}
+
+void BluetoothRemoteGattDescriptorAndroid::OnWrite(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& jcaller,
+ int32_t status) {
+ write_pending_ = false;
+
+ // Clear callbacks before calling to avoid reentrancy issues.
+ base::Closure write_callback = write_callback_;
+ ErrorCallback write_error_callback = write_error_callback_;
+ write_callback_.Reset();
+ write_error_callback_.Reset();
+
+ if (status == 0 // android.bluetooth.BluetoothGatt.GATT_SUCCESS
+ && !write_callback.is_null()) {
+ write_callback.Run();
+ // TODO(https://crbug.com/584369): Call GattDescriptorValueChanged.
+ } else if (!write_error_callback.is_null()) {
+ write_error_callback.Run(
+ BluetoothRemoteGattServiceAndroid::GetGattErrorCode(status));
+ }
}
BluetoothRemoteGattDescriptorAndroid::BluetoothRemoteGattDescriptorAndroid(
diff --git a/device/bluetooth/bluetooth_remote_gatt_descriptor_android.h b/device/bluetooth/bluetooth_remote_gatt_descriptor_android.h
index bc50d65..2b0fa58 100644
--- a/device/bluetooth/bluetooth_remote_gatt_descriptor_android.h
+++ b/device/bluetooth/bluetooth_remote_gatt_descriptor_android.h
@@ -50,6 +50,17 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattDescriptorAndroid
const base::Closure& callback,
const ErrorCallback& error_callback) override;
+ // Called when Read operation completes.
+ void OnRead(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ int32_t status,
+ const base::android::JavaParamRef<jbyteArray>& value);
+
+ // Called when Write operation completes.
+ void OnWrite(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ int32_t status);
+
private:
BluetoothRemoteGattDescriptorAndroid(const std::string& instanceId);
@@ -60,6 +71,18 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattDescriptorAndroid
// Adapter unique instance ID.
std::string instance_id_;
+ // ReadRemoteCharacteristic callbacks and pending state.
+ bool read_pending_ = false;
+ ValueCallback read_callback_;
+ ErrorCallback read_error_callback_;
+
+ // WriteRemoteCharacteristic callbacks and pending state.
+ bool write_pending_ = false;
+ base::Closure write_callback_;
+ ErrorCallback write_error_callback_;
+
+ std::vector<uint8_t> value_;
+
DISALLOW_COPY_AND_ASSIGN(BluetoothRemoteGattDescriptorAndroid);
};
diff --git a/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java b/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java
index 46f9c66..f3d98a7 100644
--- a/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java
+++ b/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java
@@ -368,6 +368,7 @@ class Fakes {
boolean mReadCharacteristicWillFailSynchronouslyOnce = false;
boolean mSetCharacteristicNotificationWillFailSynchronouslyOnce = false;
boolean mWriteCharacteristicWillFailSynchronouslyOnce = false;
+ boolean mReadDescriptorWillFailSynchronouslyOnce = false;
boolean mWriteDescriptorWillFailSynchronouslyOnce = false;
public FakeBluetoothGatt(FakeBluetoothDevice device) {
@@ -431,6 +432,16 @@ class Fakes {
}
@Override
+ boolean readDescriptor(Wrappers.BluetoothGattDescriptorWrapper descriptor) {
+ if (mReadDescriptorWillFailSynchronouslyOnce) {
+ mReadDescriptorWillFailSynchronouslyOnce = false;
+ return false;
+ }
+ nativeOnFakeBluetoothGattReadDescriptor(mDevice.mAdapter.mNativeBluetoothTestAndroid);
+ return true;
+ }
+
+ @Override
boolean writeDescriptor(Wrappers.BluetoothGattDescriptorWrapper descriptor) {
if (mWriteDescriptorWillFailSynchronouslyOnce) {
mWriteDescriptorWillFailSynchronouslyOnce = false;
@@ -686,15 +697,65 @@ class Fakes {
final FakeBluetoothGattCharacteristic mCharacteristic;
final UUID mUuid;
byte[] mValue;
+ static FakeBluetoothGattDescriptor sRememberedDescriptor;
public FakeBluetoothGattDescriptor(
FakeBluetoothGattCharacteristic characteristic, UUID uuid) {
- super(null);
+ super(null, null);
mCharacteristic = characteristic;
mUuid = uuid;
mValue = new byte[0];
}
+ // Implements BluetoothTestAndroid::RememberDescriptorForSubsequentAction.
+ @CalledByNative("FakeBluetoothGattDescriptor")
+ private static void rememberDescriptorForSubsequentAction(
+ ChromeBluetoothRemoteGattDescriptor chromeDescriptor) {
+ sRememberedDescriptor = (FakeBluetoothGattDescriptor) chromeDescriptor.mDescriptor;
+ }
+
+ // Simulate a value being read from a descriptor.
+ @CalledByNative("FakeBluetoothGattDescriptor")
+ private static void valueRead(
+ ChromeBluetoothRemoteGattDescriptor chromeDescriptor, int status, byte[] value) {
+ if (chromeDescriptor == null && sRememberedDescriptor == null)
+ throw new IllegalArgumentException("rememberDescriptor wasn't called previously.");
+
+ FakeBluetoothGattDescriptor fakeDescriptor = (chromeDescriptor == null)
+ ? sRememberedDescriptor
+ : (FakeBluetoothGattDescriptor) chromeDescriptor.mDescriptor;
+
+ fakeDescriptor.mValue = value;
+ fakeDescriptor.mCharacteristic.mService.mDevice.mGattCallback.onDescriptorRead(
+ fakeDescriptor, status);
+ }
+
+ // Simulate a value being written to a descriptor.
+ @CalledByNative("FakeBluetoothGattDescriptor")
+ private static void valueWrite(
+ ChromeBluetoothRemoteGattDescriptor chromeDescriptor, int status) {
+ if (chromeDescriptor == null && sRememberedDescriptor == null)
+ throw new IllegalArgumentException("rememberDescriptor wasn't called previously.");
+
+ FakeBluetoothGattDescriptor fakeDescriptor = (chromeDescriptor == null)
+ ? sRememberedDescriptor
+ : (FakeBluetoothGattDescriptor) chromeDescriptor.mDescriptor;
+
+ fakeDescriptor.mCharacteristic.mService.mDevice.mGattCallback.onDescriptorWrite(
+ fakeDescriptor, status);
+ }
+
+ // Cause subsequent value read of a descriptor to fail synchronously.
+ @CalledByNative("FakeBluetoothGattDescriptor")
+ private static void setReadDescriptorWillFailSynchronouslyOnce(
+ ChromeBluetoothRemoteGattDescriptor chromeDescriptor) {
+ FakeBluetoothGattDescriptor fakeDescriptor =
+ (FakeBluetoothGattDescriptor) chromeDescriptor.mDescriptor;
+
+ fakeDescriptor.mCharacteristic.mService.mDevice.mGatt
+ .mReadDescriptorWillFailSynchronouslyOnce = true;
+ }
+
// Cause subsequent value write of a descriptor to fail synchronously.
@CalledByNative("FakeBluetoothGattDescriptor")
private static void setWriteDescriptorWillFailSynchronouslyOnce(
@@ -710,6 +771,11 @@ class Fakes {
// Wrappers.BluetoothGattDescriptorWrapper overrides:
@Override
+ public Wrappers.BluetoothGattCharacteristicWrapper getCharacteristic() {
+ return mCharacteristic;
+ }
+
+ @Override
public UUID getUuid() {
return mUuid;
}
@@ -759,6 +825,10 @@ class Fakes {
private static native void nativeOnFakeBluetoothGattWriteCharacteristic(
long nativeBluetoothTestAndroid, byte[] value);
+ // Binds to BluetoothTestAndroid::OnFakeBluetoothGattReadDescriptor.
+ private static native void nativeOnFakeBluetoothGattReadDescriptor(
+ long nativeBluetoothTestAndroid);
+
// Binds to BluetoothTestAndroid::OnFakeBluetoothGattWriteDescriptor.
private static native void nativeOnFakeBluetoothGattWriteDescriptor(
long nativeBluetoothTestAndroid, byte[] value);
diff --git a/device/bluetooth/test/bluetooth_test.cc b/device/bluetooth/test/bluetooth_test.cc
index 5feec01..77ecddc 100644
--- a/device/bluetooth/test/bluetooth_test.cc
+++ b/device/bluetooth/test/bluetooth_test.cc
@@ -231,6 +231,7 @@ void BluetoothTestBase::ResetEventCounts() {
gatt_notify_characteristic_attempts_ = 0;
gatt_read_characteristic_attempts_ = 0;
gatt_write_characteristic_attempts_ = 0;
+ gatt_read_descriptor_attempts_ = 0;
gatt_write_descriptor_attempts_ = 0;
}
diff --git a/device/bluetooth/test/bluetooth_test.h b/device/bluetooth/test/bluetooth_test.h
index 5570ca1..c840935 100644
--- a/device/bluetooth/test/bluetooth_test.h
+++ b/device/bluetooth/test/bluetooth_test.h
@@ -189,6 +189,41 @@ class BluetoothTestBase : public testing::Test {
BluetoothGattCharacteristic* characteristic,
const std::string& uuid) {}
+ // Remembers |descriptor|'s platform specific object to be used in a
+ // subsequent call to methods such as SimulateGattDescriptorRead that
+ // accept a nullptr value to select this remembered descriptor. This
+ // enables tests where the platform attempts to reference descriptor
+ // objects after the Chrome objects have been deleted, e.g. with DeleteDevice.
+ virtual void RememberDescriptorForSubsequentAction(
+ BluetoothGattDescriptor* descriptor) {}
+
+ // Simulates a Descriptor Read operation succeeding, returning |value|.
+ // If |descriptor| is null, acts upon the descriptor provided to
+ // RememberDescriptorForSubsequentAction.
+ virtual void SimulateGattDescriptorRead(BluetoothGattDescriptor* descriptor,
+ const std::vector<uint8_t>& value) {}
+
+ // Simulates a Descriptor Read operation failing with a GattErrorCode.
+ virtual void SimulateGattDescriptorReadError(
+ BluetoothGattDescriptor* descriptor,
+ BluetoothGattService::GattErrorCode) {}
+
+ // Simulates a Descriptor Read operation failing synchronously once for an
+ // unknown reason.
+ virtual void SimulateGattDescriptorReadWillFailSynchronouslyOnce(
+ BluetoothGattDescriptor* descriptor) {}
+
+ // Simulates a Descriptor Write operation succeeding, returning |value|.
+ // If |descriptor| is null, acts upon the descriptor provided to
+ // RememberDescriptorForSubsequentAction.
+ virtual void SimulateGattDescriptorWrite(
+ BluetoothGattDescriptor* descriptor) {}
+
+ // Simulates a Descriptor Write operation failing with a GattErrorCode.
+ virtual void SimulateGattDescriptorWriteError(
+ BluetoothGattDescriptor* descriptor,
+ BluetoothGattService::GattErrorCode) {}
+
// Simulates a Descriptor Write operation failing synchronously once for
// an unknown reason.
virtual void SimulateGattDescriptorWriteWillFailSynchronouslyOnce(
@@ -250,6 +285,7 @@ class BluetoothTestBase : public testing::Test {
int gatt_notify_characteristic_attempts_ = 0;
int gatt_read_characteristic_attempts_ = 0;
int gatt_write_characteristic_attempts_ = 0;
+ int gatt_read_descriptor_attempts_ = 0;
int gatt_write_descriptor_attempts_ = 0;
// The following values are used to make sure the correct callbacks
diff --git a/device/bluetooth/test/bluetooth_test_android.cc b/device/bluetooth/test/bluetooth_test_android.cc
index 522cd61..b1cd357 100644
--- a/device/bluetooth/test/bluetooth_test_android.cc
+++ b/device/bluetooth/test/bluetooth_test_android.cc
@@ -176,10 +176,14 @@ void BluetoothTestAndroid::RememberCharacteristicForSubsequentAction(
void BluetoothTestAndroid::SimulateGattNotifySessionStarted(
BluetoothGattCharacteristic* characteristic) {
- // Android doesn't provide any sort of callback for when notifications have
- // been enabled. So, just run the message loop to process the success
- // callback.
- base::RunLoop().RunUntilIdle();
+ BluetoothGattDescriptor* descriptor = characteristic->GetDescriptorForUUID(
+ BluetoothGattDescriptor::ClientCharacteristicConfigurationUuid());
+ BluetoothRemoteGattDescriptorAndroid* descriptor_android =
+ static_cast<BluetoothRemoteGattDescriptorAndroid*>(descriptor);
+ Java_FakeBluetoothGattDescriptor_valueWrite(
+ base::android::AttachCurrentThread(),
+ descriptor_android ? descriptor_android->GetJavaObject().obj() : nullptr,
+ 0); // android.bluetooth.BluetoothGatt.GATT_SUCCESS
}
void BluetoothTestAndroid::
@@ -291,6 +295,75 @@ void BluetoothTestAndroid::SimulateGattDescriptor(
base::android::ConvertUTF8ToJavaString(env, uuid).obj());
}
+void BluetoothTestAndroid::RememberDescriptorForSubsequentAction(
+ BluetoothGattDescriptor* descriptor) {
+ BluetoothRemoteGattDescriptorAndroid* descriptor_android =
+ static_cast<BluetoothRemoteGattDescriptorAndroid*>(descriptor);
+
+ Java_FakeBluetoothGattDescriptor_rememberDescriptorForSubsequentAction(
+ base::android::AttachCurrentThread(),
+ descriptor_android->GetJavaObject().obj());
+}
+
+void BluetoothTestAndroid::SimulateGattDescriptorRead(
+ BluetoothGattDescriptor* descriptor,
+ const std::vector<uint8_t>& value) {
+ BluetoothRemoteGattDescriptorAndroid* descriptor_android =
+ static_cast<BluetoothRemoteGattDescriptorAndroid*>(descriptor);
+ JNIEnv* env = base::android::AttachCurrentThread();
+
+ Java_FakeBluetoothGattDescriptor_valueRead(
+ env,
+ descriptor_android ? descriptor_android->GetJavaObject().obj() : nullptr,
+ 0, // android.bluetooth.BluetoothGatt.GATT_SUCCESS
+ base::android::ToJavaByteArray(env, value).obj());
+}
+
+void BluetoothTestAndroid::SimulateGattDescriptorReadError(
+ BluetoothGattDescriptor* descriptor,
+ BluetoothGattService::GattErrorCode error_code) {
+ BluetoothRemoteGattDescriptorAndroid* descriptor_android =
+ static_cast<BluetoothRemoteGattDescriptorAndroid*>(descriptor);
+ JNIEnv* env = base::android::AttachCurrentThread();
+ std::vector<uint8_t> empty_value;
+
+ Java_FakeBluetoothGattDescriptor_valueRead(
+ env, descriptor_android->GetJavaObject().obj(),
+ BluetoothRemoteGattServiceAndroid::GetAndroidErrorCode(error_code),
+ base::android::ToJavaByteArray(env, empty_value).obj());
+}
+
+void BluetoothTestAndroid::SimulateGattDescriptorReadWillFailSynchronouslyOnce(
+ BluetoothGattDescriptor* descriptor) {
+ BluetoothRemoteGattDescriptorAndroid* descriptor_android =
+ static_cast<BluetoothRemoteGattDescriptorAndroid*>(descriptor);
+ JNIEnv* env = base::android::AttachCurrentThread();
+
+ Java_FakeBluetoothGattDescriptor_setReadDescriptorWillFailSynchronouslyOnce(
+ env, descriptor_android->GetJavaObject().obj());
+}
+
+void BluetoothTestAndroid::SimulateGattDescriptorWrite(
+ BluetoothGattDescriptor* descriptor) {
+ BluetoothRemoteGattDescriptorAndroid* descriptor_android =
+ static_cast<BluetoothRemoteGattDescriptorAndroid*>(descriptor);
+ Java_FakeBluetoothGattDescriptor_valueWrite(
+ base::android::AttachCurrentThread(),
+ descriptor_android ? descriptor_android->GetJavaObject().obj() : nullptr,
+ 0); // android.bluetooth.BluetoothGatt.GATT_SUCCESS
+}
+
+void BluetoothTestAndroid::SimulateGattDescriptorWriteError(
+ BluetoothGattDescriptor* descriptor,
+ BluetoothGattService::GattErrorCode error_code) {
+ BluetoothRemoteGattDescriptorAndroid* descriptor_android =
+ static_cast<BluetoothRemoteGattDescriptorAndroid*>(descriptor);
+ Java_FakeBluetoothGattDescriptor_valueWrite(
+ base::android::AttachCurrentThread(),
+ descriptor_android->GetJavaObject().obj(),
+ BluetoothRemoteGattServiceAndroid::GetAndroidErrorCode(error_code));
+}
+
void BluetoothTestAndroid::SimulateGattDescriptorWriteWillFailSynchronouslyOnce(
BluetoothGattDescriptor* descriptor) {
BluetoothRemoteGattDescriptorAndroid* descriptor_android =
@@ -348,6 +421,12 @@ void BluetoothTestAndroid::OnFakeBluetoothGattWriteCharacteristic(
base::android::JavaByteArrayToByteVector(env, value, &last_write_value_);
}
+void BluetoothTestAndroid::OnFakeBluetoothGattReadDescriptor(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& caller) {
+ gatt_read_descriptor_attempts_++;
+}
+
void BluetoothTestAndroid::OnFakeBluetoothGattWriteDescriptor(
JNIEnv* env,
const JavaParamRef<jobject>& caller,
diff --git a/device/bluetooth/test/bluetooth_test_android.h b/device/bluetooth/test/bluetooth_test_android.h
index b855eca..8fbf61c 100644
--- a/device/bluetooth/test/bluetooth_test_android.h
+++ b/device/bluetooth/test/bluetooth_test_android.h
@@ -51,6 +51,7 @@ class BluetoothTestAndroid : public BluetoothTestBase {
void SimulateGattCharacteristicChanged(
BluetoothGattCharacteristic* characteristic,
const std::vector<uint8_t>& value) override;
+
void SimulateGattCharacteristicRead(
BluetoothGattCharacteristic* characteristic,
const std::vector<uint8_t>& value) override;
@@ -59,6 +60,7 @@ class BluetoothTestAndroid : public BluetoothTestBase {
BluetoothGattService::GattErrorCode) override;
void SimulateGattCharacteristicReadWillFailSynchronouslyOnce(
BluetoothGattCharacteristic* characteristic) override;
+
void SimulateGattCharacteristicWrite(
BluetoothGattCharacteristic* characteristic) override;
void SimulateGattCharacteristicWriteError(
@@ -66,8 +68,25 @@ class BluetoothTestAndroid : public BluetoothTestBase {
BluetoothGattService::GattErrorCode) override;
void SimulateGattCharacteristicWriteWillFailSynchronouslyOnce(
BluetoothGattCharacteristic* characteristic) override;
+
void SimulateGattDescriptor(BluetoothGattCharacteristic* characteristic,
const std::string& uuid) override;
+ void RememberDescriptorForSubsequentAction(
+ BluetoothGattDescriptor* descriptor) override;
+
+ void SimulateGattDescriptorRead(BluetoothGattDescriptor* descriptor,
+ const std::vector<uint8_t>& value) override;
+ void SimulateGattDescriptorReadError(
+ BluetoothGattDescriptor* descriptor,
+ BluetoothGattService::GattErrorCode) override;
+ void SimulateGattDescriptorReadWillFailSynchronouslyOnce(
+ BluetoothGattDescriptor* descriptor) override;
+
+ void SimulateGattDescriptorWrite(
+ BluetoothGattDescriptor* descriptor) override;
+ void SimulateGattDescriptorWriteError(
+ BluetoothGattDescriptor* descriptor,
+ BluetoothGattService::GattErrorCode) override;
void SimulateGattDescriptorWriteWillFailSynchronouslyOnce(
BluetoothGattDescriptor* descriptor) override;
@@ -112,6 +131,11 @@ class BluetoothTestAndroid : public BluetoothTestBase {
const base::android::JavaParamRef<jobject>& caller,
const base::android::JavaParamRef<jbyteArray>& value);
+ // Records that Java FakeBluetoothGatt readDescriptor was called.
+ void OnFakeBluetoothGattReadDescriptor(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& caller);
+
// Records that Java FakeBluetoothGatt writeDescriptor was called.
void OnFakeBluetoothGattWriteDescriptor(
JNIEnv* env,