// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.device.bluetooth;
import org.jni_zero.CalledByNative;
import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods;
import org.chromium.base.Log;
import java.util.List;
/**
* Exposes android.bluetooth.BluetoothGattCharacteristic as necessary
* for C++ device::BluetoothRemoteGattCharacteristicAndroid.
*
* Lifetime is controlled by
* device::BluetoothRemoteGattCharacteristicAndroid.
*/
@JNINamespace("device")
final class ChromeBluetoothRemoteGattCharacteristic {
private static final String TAG = "Bluetooth";
private long mNativeBluetoothRemoteGattCharacteristicAndroid;
final Wrappers.BluetoothGattCharacteristicWrapper mCharacteristic;
final String mInstanceId;
final ChromeBluetoothDevice mChromeDevice;
private ChromeBluetoothRemoteGattCharacteristic(
long nativeBluetoothRemoteGattCharacteristicAndroid,
Wrappers.BluetoothGattCharacteristicWrapper characteristicWrapper,
String instanceId,
ChromeBluetoothDevice chromeDevice) {
mNativeBluetoothRemoteGattCharacteristicAndroid =
nativeBluetoothRemoteGattCharacteristicAndroid;
mCharacteristic = characteristicWrapper;
mInstanceId = instanceId;
mChromeDevice = chromeDevice;
mChromeDevice.mWrapperToChromeCharacteristicsMap.put(characteristicWrapper, this);
Log.v(TAG, "ChromeBluetoothRemoteGattCharacteristic created.");
}
/** Handles C++ object being destroyed. */
@CalledByNative
private void onBluetoothRemoteGattCharacteristicAndroidDestruction() {
Log.v(TAG, "ChromeBluetoothRemoteGattCharacteristic Destroyed.");
if (mChromeDevice.mBluetoothGatt != null) {
mChromeDevice.mBluetoothGatt.setCharacteristicNotification(mCharacteristic, false);
}
mNativeBluetoothRemoteGattCharacteristicAndroid = 0;
mChromeDevice.mWrapperToChromeCharacteristicsMap.remove(mCharacteristic);
}
void onCharacteristicChanged(byte[] value) {
Log.i(TAG, "onCharacteristicChanged");
if (mNativeBluetoothRemoteGattCharacteristicAndroid != 0) {
ChromeBluetoothRemoteGattCharacteristicJni.get()
.onChanged(
mNativeBluetoothRemoteGattCharacteristicAndroid,
ChromeBluetoothRemoteGattCharacteristic.this,
value);
}
}
void onCharacteristicRead(int status) {
Log.i(
TAG,
"onCharacteristicRead status:%d==%s",
status,
status == android.bluetooth.BluetoothGatt.GATT_SUCCESS ? "OK" : "Error");
if (mNativeBluetoothRemoteGattCharacteristicAndroid != 0) {
ChromeBluetoothRemoteGattCharacteristicJni.get()
.onRead(
mNativeBluetoothRemoteGattCharacteristicAndroid,
ChromeBluetoothRemoteGattCharacteristic.this,
status,
mCharacteristic.getValue());
}
}
void onCharacteristicWrite(int status) {
Log.i(
TAG,
"onCharacteristicWrite status:%d==%s",
status,
status == android.bluetooth.BluetoothGatt.GATT_SUCCESS ? "OK" : "Error");
if (mNativeBluetoothRemoteGattCharacteristicAndroid != 0) {
ChromeBluetoothRemoteGattCharacteristicJni.get()
.onWrite(
mNativeBluetoothRemoteGattCharacteristicAndroid,
ChromeBluetoothRemoteGattCharacteristic.this,
status);
}
}
// ---------------------------------------------------------------------------------------------
// BluetoothRemoteGattCharacteristicAndroid methods implemented in java:
// Implements BluetoothRemoteGattCharacteristicAndroid::Create.
@CalledByNative
private static ChromeBluetoothRemoteGattCharacteristic create(
long nativeBluetoothRemoteGattCharacteristicAndroid,
Wrappers.BluetoothGattCharacteristicWrapper characteristicWrapper,
String instanceId,
ChromeBluetoothDevice chromeDevice) {
return new ChromeBluetoothRemoteGattCharacteristic(
nativeBluetoothRemoteGattCharacteristicAndroid,
characteristicWrapper,
instanceId,
chromeDevice);
}
// Implements BluetoothRemoteGattCharacteristicAndroid::GetUUID.
@CalledByNative
private String getUUID() {
return mCharacteristic.getUuid().toString();
}
// Implements BluetoothRemoteGattCharacteristicAndroid::GetProperties.
@CalledByNative
private int getProperties() {
// TODO(scheib): Must read Extended Properties Descriptor. crbug.com/548449
return mCharacteristic.getProperties();
}
// Implements BluetoothRemoteGattCharacteristicAndroid::ReadRemoteCharacteristic.
@CalledByNative
private boolean readRemoteCharacteristic() {
if (!mChromeDevice.mBluetoothGatt.readCharacteristic(mCharacteristic)) {
Log.i(TAG, "readRemoteCharacteristic readCharacteristic failed.");
return false;
}
return true;
}
// Implements BluetoothRemoteGattCharacteristicAndroid::WriteRemoteCharacteristic.
@CalledByNative
private boolean writeRemoteCharacteristic(byte[] value, int writeType) {
if (!mCharacteristic.setValue(value)) {
Log.i(TAG, "writeRemoteCharacteristic setValue failed.");
return false;
}
if (writeType != 0) {
mCharacteristic.setWriteType(writeType);
}
if (!mChromeDevice.mBluetoothGatt.writeCharacteristic(mCharacteristic)) {
Log.i(TAG, "writeRemoteCharacteristic writeCharacteristic failed.");
return false;
}
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
private void createDescriptors() {
List<Wrappers.BluetoothGattDescriptorWrapper> descriptors =
mCharacteristic.getDescriptors();
// descriptorInstanceId ensures duplicate UUIDs have unique instance
// IDs. BluetoothGattDescriptor does not offer getInstanceId the way
// BluetoothGattCharacteristic does.
//
// TODO(crbug.com/40452041) Do not reuse IDs upon onServicesDiscovered.
int instanceIdCounter = 0;
for (Wrappers.BluetoothGattDescriptorWrapper descriptor : descriptors) {
String descriptorInstanceId =
mInstanceId + "/" + descriptor.getUuid().toString() + ";" + instanceIdCounter++;
ChromeBluetoothRemoteGattCharacteristicJni.get()
.createGattRemoteDescriptor(
mNativeBluetoothRemoteGattCharacteristicAndroid,
ChromeBluetoothRemoteGattCharacteristic.this,
descriptorInstanceId,
descriptor,
mChromeDevice);
}
}
@NativeMethods
interface Natives {
// Binds to BluetoothRemoteGattCharacteristicAndroid::OnChanged.
void onChanged(
long nativeBluetoothRemoteGattCharacteristicAndroid,
ChromeBluetoothRemoteGattCharacteristic caller,
byte[] value);
// Binds to BluetoothRemoteGattCharacteristicAndroid::OnRead.
void onRead(
long nativeBluetoothRemoteGattCharacteristicAndroid,
ChromeBluetoothRemoteGattCharacteristic caller,
int status,
byte[] value);
// Binds to BluetoothRemoteGattCharacteristicAndroid::OnWrite.
void onWrite(
long nativeBluetoothRemoteGattCharacteristicAndroid,
ChromeBluetoothRemoteGattCharacteristic caller,
int status);
// Binds to BluetoothRemoteGattCharacteristicAndroid::CreateGattRemoteDescriptor.
void createGattRemoteDescriptor(
long nativeBluetoothRemoteGattCharacteristicAndroid,
ChromeBluetoothRemoteGattCharacteristic caller,
String instanceId,
Wrappers.BluetoothGattDescriptorWrapper descriptorWrapper,
ChromeBluetoothDevice chromeBluetoothDevice);
}
}