Skip to content

Commit

Permalink
bluetooth: android: Create BluetoothRemoteGattServiceAndroid objects.
Browse files Browse the repository at this point in the history
Initiate GATT service discovery when a connection is established. Upon
discovery completion create C++ objects associated with the Java objects.
For now these are simple stubs, and don't even retain the Java object.

BUG=541355

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

Cr-Commit-Position: refs/heads/master@{#353465}
  • Loading branch information
scheib authored and Commit bot committed Oct 10, 2015
1 parent 62a56e1 commit c3ecc9f
Show file tree
Hide file tree
Showing 15 changed files with 427 additions and 3 deletions.
2 changes: 2 additions & 0 deletions device/bluetooth/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ component("bluetooth") {
"bluetooth_remote_gatt_characteristic_chromeos.h",
"bluetooth_remote_gatt_descriptor_chromeos.cc",
"bluetooth_remote_gatt_descriptor_chromeos.h",
"bluetooth_remote_gatt_service_android.cc",
"bluetooth_remote_gatt_service_android.h",
"bluetooth_remote_gatt_service_chromeos.cc",
"bluetooth_remote_gatt_service_chromeos.h",
"bluetooth_rfcomm_channel_mac.h",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ public void onConnectionStateChange(final int status, final int newState) {
(newState == android.bluetooth.BluetoothProfile.STATE_CONNECTED)
? "Connected"
: "Disconnected");
if (newState == android.bluetooth.BluetoothProfile.STATE_CONNECTED) {
mBluetoothGatt.discoverServices();
}
ThreadUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
Expand All @@ -149,6 +152,24 @@ public void run() {
}
});
}

@Override
public void onServicesDiscovered(final int status) {
Log.i(TAG, "onServicesDiscovered status:%d==%s", status,
status == android.bluetooth.BluetoothGatt.GATT_SUCCESS ? "OK" : "Error");
ThreadUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
if (mNativeBluetoothDeviceAndroid != 0) {
for (Wrappers.BluetoothGattServiceWrapper service :
mBluetoothGatt.getServices()) {
nativeCreateGattRemoteService(mNativeBluetoothDeviceAndroid,
service.getInstanceId(), service);
}
}
}
});
}
}

// ---------------------------------------------------------------------------------------------
Expand All @@ -157,4 +178,11 @@ public void run() {
// Binds to BluetoothDeviceAndroid::OnConnectionStateChange.
private native void nativeOnConnectionStateChange(
long nativeBluetoothDeviceAndroid, int status, boolean connected);

// Binds to BluetoothDeviceAndroid::CreateGattRemoteService.
// 'Object' type must be used for |bluetoothGattServiceWrapper| because inner class
// Wrappers.BluetoothGattServiceWrapper reference is not handled by jni_generator.py JavaToJni.
// http://crbug.com/505554
private native void nativeCreateGattRemoteService(
long nativeBluetoothDeviceAndroid, int instanceId, Object bluetoothGattServiceWrapper);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
Expand Down Expand Up @@ -264,6 +265,20 @@ static class BluetoothGattWrapper {
public void disconnect() {
mGatt.disconnect();
}

public void discoverServices() {
mGatt.discoverServices();
}

public List<BluetoothGattServiceWrapper> getServices() {
List<BluetoothGattService> services = mGatt.getServices();
ArrayList<BluetoothGattServiceWrapper> servicesWrapped =
new ArrayList<BluetoothGattServiceWrapper>(services.size());
for (BluetoothGattService service : services) {
servicesWrapped.add(new BluetoothGattServiceWrapper(service));
}
return servicesWrapped;
}
}

/**
Expand All @@ -285,6 +300,11 @@ static class ForwardBluetoothGattCallbackToWrapper extends BluetoothGattCallback
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
mWrapperCallback.onConnectionStateChange(status, newState);
}

@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
mWrapperCallback.onServicesDiscovered(status);
}
}

/**
Expand All @@ -297,5 +317,21 @@ public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState
*/
abstract static class BluetoothGattCallbackWrapper {
public abstract void onConnectionStateChange(int status, int newState);
public abstract void onServicesDiscovered(int status);
}

/**
* Wraps android.bluetooth.BluetoothGattService.
*/
static class BluetoothGattServiceWrapper {
private final BluetoothGattService mService;

public BluetoothGattServiceWrapper(BluetoothGattService service) {
mService = service;
}

public int getInstanceId() {
return mService.getInstanceId();
}
}
}
2 changes: 2 additions & 0 deletions device/bluetooth/bluetooth.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@
'bluetooth_remote_gatt_characteristic_chromeos.h',
'bluetooth_remote_gatt_descriptor_chromeos.cc',
'bluetooth_remote_gatt_descriptor_chromeos.h',
'bluetooth_remote_gatt_service_android.cc',
'bluetooth_remote_gatt_service_android.h',
'bluetooth_remote_gatt_service_chromeos.cc',
'bluetooth_remote_gatt_service_chromeos.h',
'bluetooth_rfcomm_channel_mac.mm',
Expand Down
8 changes: 8 additions & 0 deletions device/bluetooth/bluetooth_adapter_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterAndroid final
const CreateAdvertisementCallback& callback,
const CreateAdvertisementErrorCallback& error_callback) override;

// Returns BluetoothAdapter Observers for use by Android platform
// implementation classes to send event notifications. Intentionally not
// exposed on the public base class BluetoothAdapter as it is an
// implementation detail.
base::ObserverList<device::BluetoothAdapter::Observer>& GetObservers() {
return observers_;
}

// Handles a scan error event by invalidating all discovery sessions.
void OnScanFailed(JNIEnv* env, jobject caller);

Expand Down
25 changes: 25 additions & 0 deletions device/bluetooth/bluetooth_device_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/strings/stringprintf.h"
#include "device/bluetooth/bluetooth_adapter_android.h"
#include "device/bluetooth/bluetooth_remote_gatt_service_android.h"
#include "jni/ChromeBluetoothDevice_jni.h"

using base::android::AttachCurrentThread;
Expand Down Expand Up @@ -221,6 +223,29 @@ void BluetoothDeviceAndroid::OnConnectionStateChange(JNIEnv* env,
}
}

void BluetoothDeviceAndroid::CreateGattRemoteService(
JNIEnv* env,
jobject caller,
int32_t instanceId,
jobject bluetooth_gatt_service_wrapper // Java Type:
// BluetoothGattServiceWrapper
) {
std::string instanceIdString = base::StringPrintf("%d", instanceId);

if (gatt_services_.contains(instanceIdString))
return;

BluetoothRemoteGattServiceAndroid* service =
BluetoothRemoteGattServiceAndroid::Create(
GetAdapter(), this, bluetooth_gatt_service_wrapper, instanceIdString);

gatt_services_.set(instanceIdString,
make_scoped_ptr<BluetoothGattService>(service));

FOR_EACH_OBSERVER(BluetoothAdapter::Observer, GetAdapter()->GetObservers(),
GattServiceAdded(adapter_, this, service));
}

BluetoothDeviceAndroid::BluetoothDeviceAndroid(BluetoothAdapterAndroid* adapter)
: BluetoothDevice(adapter) {}

Expand Down
17 changes: 15 additions & 2 deletions device/bluetooth/bluetooth_device_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@

#include "base/android/jni_android.h"
#include "base/memory/weak_ptr.h"
#include "device/bluetooth/bluetooth_adapter_android.h"
#include "device/bluetooth/bluetooth_device.h"

namespace device {

class BluetoothAdapterAndroid;

// BluetoothDeviceAndroid along with the Java class
// org.chromium.device.bluetooth.ChromeBluetoothDevice implement
// BluetoothDevice.
Expand All @@ -39,6 +38,11 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothDeviceAndroid final
// Returns the associated ChromeBluetoothDevice Java object.
base::android::ScopedJavaLocalRef<jobject> GetJavaObject();

// Get owning BluetoothAdapter cast to BluetoothAdapterAndroid.
BluetoothAdapterAndroid* GetAdapter() {
return static_cast<BluetoothAdapterAndroid*>(adapter_);
}

// Updates cached copy of advertised UUIDs discovered during a scan.
// Returns true if new UUIDs differed from cached values.
bool UpdateAdvertisedUUIDs(
Expand Down Expand Up @@ -90,6 +94,15 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothDeviceAndroid final
int32_t status,
bool connected);

// Creates Bluetooth GATT service objects and adds them to
// BluetoothDevice::gatt_services_ if they are not already there.
void CreateGattRemoteService(
JNIEnv* env,
jobject caller,
int32_t instanceId,
jobject bluetooth_gatt_service_wrapper); // Java Type:
// BluetoothGattServiceWrapper

protected:
BluetoothDeviceAndroid(BluetoothAdapterAndroid* adapter);

Expand Down
34 changes: 34 additions & 0 deletions device/bluetooth/bluetooth_device_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -425,4 +425,38 @@ TEST_F(BluetoothTest, BluetoothGattConnection_ErrorAfterConnection) {
}
#endif // defined(OS_ANDROID)

#if defined(OS_ANDROID)
TEST_F(BluetoothTest, SimulateGattServicesDiscovered) {
InitWithFakeAdapter();
StartDiscoverySession();
BluetoothDevice* device = DiscoverLowEnergyDevice(3);
device->CreateGattConnection(GetGattConnectionCallback(),
GetConnectErrorCallback());
ResetEventCounts();
SimulateGattConnection(device);
EXPECT_EQ(1, gatt_discovery_attempts_);

// TODO(scheib): Add more control over how many services are created and
// their properties. http://crbug.com/541400
SimulateGattServicesDiscovered(device);
EXPECT_EQ(2u, device->GetGattServices().size());
}
#endif // defined(OS_ANDROID)

#if defined(OS_ANDROID)
TEST_F(BluetoothTest, SimulateGattServicesDiscoveryError) {
InitWithFakeAdapter();
StartDiscoverySession();
BluetoothDevice* device = DiscoverLowEnergyDevice(3);
device->CreateGattConnection(GetGattConnectionCallback(),
GetConnectErrorCallback());
ResetEventCounts();
SimulateGattConnection(device);
EXPECT_EQ(1, gatt_discovery_attempts_);

SimulateGattServicesDiscoveryError(device);
EXPECT_EQ(0u, device->GetGattServices().size());
}
#endif // defined(OS_ANDROID)

} // namespace device
96 changes: 96 additions & 0 deletions device/bluetooth/bluetooth_remote_gatt_service_android.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// 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.

#include "device/bluetooth/bluetooth_remote_gatt_service_android.h"

#include "device/bluetooth/bluetooth_adapter_android.h"
#include "device/bluetooth/bluetooth_device_android.h"

namespace device {

// static
BluetoothRemoteGattServiceAndroid* BluetoothRemoteGattServiceAndroid::Create(
BluetoothAdapterAndroid* adapter,
BluetoothDeviceAndroid* device,
jobject bluetooth_remote_gatt_service_wrapper,
std::string instanceId) {
BluetoothRemoteGattServiceAndroid* service =
new BluetoothRemoteGattServiceAndroid(adapter, device, instanceId);

return service;
}

std::string BluetoothRemoteGattServiceAndroid::GetIdentifier() const {
return instanceId_;
}

device::BluetoothUUID BluetoothRemoteGattServiceAndroid::GetUUID() const {
NOTIMPLEMENTED();
return device::BluetoothUUID();
}

bool BluetoothRemoteGattServiceAndroid::IsLocal() const {
return false;
}

bool BluetoothRemoteGattServiceAndroid::IsPrimary() const {
NOTIMPLEMENTED();
return true;
}

device::BluetoothDevice* BluetoothRemoteGattServiceAndroid::GetDevice() const {
return device_;
}

std::vector<device::BluetoothGattCharacteristic*>
BluetoothRemoteGattServiceAndroid::GetCharacteristics() const {
NOTIMPLEMENTED();
std::vector<device::BluetoothGattCharacteristic*> characteristics;
return characteristics;
}

std::vector<device::BluetoothGattService*>
BluetoothRemoteGattServiceAndroid::GetIncludedServices() const {
NOTIMPLEMENTED();
return std::vector<device::BluetoothGattService*>();
}

device::BluetoothGattCharacteristic*
BluetoothRemoteGattServiceAndroid::GetCharacteristic(
const std::string& identifier) const {
NOTIMPLEMENTED();
return nullptr;
}

bool BluetoothRemoteGattServiceAndroid::AddCharacteristic(
device::BluetoothGattCharacteristic* characteristic) {
return false;
}

bool BluetoothRemoteGattServiceAndroid::AddIncludedService(
device::BluetoothGattService* service) {
return false;
}

void BluetoothRemoteGattServiceAndroid::Register(
const base::Closure& callback,
const ErrorCallback& error_callback) {
error_callback.Run();
}

void BluetoothRemoteGattServiceAndroid::Unregister(
const base::Closure& callback,
const ErrorCallback& error_callback) {
error_callback.Run();
}

BluetoothRemoteGattServiceAndroid::BluetoothRemoteGattServiceAndroid(
BluetoothAdapterAndroid* adapter,
BluetoothDeviceAndroid* device,
std::string instanceId)
: adapter_(adapter), device_(device), instanceId_(instanceId) {}

BluetoothRemoteGattServiceAndroid::~BluetoothRemoteGattServiceAndroid() {}

} // namespace device
Loading

0 comments on commit c3ecc9f

Please sign in to comment.