chromium/device/bluetooth/bluetooth_remote_gatt_service_android.cc

// Copyright 2014 The Chromium Authors
// 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 <memory>

#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/containers/contains.h"
#include "base/logging.h"
#include "device/bluetooth/bluetooth_adapter_android.h"
#include "device/bluetooth/bluetooth_device_android.h"
#include "device/bluetooth/bluetooth_remote_gatt_characteristic_android.h"

// Must come after all headers that specialize FromJniType() / ToJniType().
#include "device/bluetooth/jni_headers/ChromeBluetoothRemoteGattService_jni.h"

using base::android::AttachCurrentThread;
using base::android::JavaParamRef;
using base::android::JavaRef;

namespace device {

// static
std::unique_ptr<BluetoothRemoteGattServiceAndroid>
BluetoothRemoteGattServiceAndroid::Create(
    BluetoothAdapterAndroid* adapter,
    BluetoothDeviceAndroid* device,
    const JavaRef<jobject>&
        bluetooth_gatt_service_wrapper,  // BluetoothGattServiceWrapper
    const std::string& instance_id,
    const JavaRef<jobject>& chrome_bluetooth_device) {  // ChromeBluetoothDevice
  std::unique_ptr<BluetoothRemoteGattServiceAndroid> service(
      new BluetoothRemoteGattServiceAndroid(adapter, device, instance_id));

  JNIEnv* env = AttachCurrentThread();
  service->j_service_.Reset(Java_ChromeBluetoothRemoteGattService_create(
      env, reinterpret_cast<intptr_t>(service.get()),
      bluetooth_gatt_service_wrapper,
      base::android::ConvertUTF8ToJavaString(env, instance_id),
      chrome_bluetooth_device));

  return service;
}

BluetoothRemoteGattServiceAndroid::~BluetoothRemoteGattServiceAndroid() {
  Java_ChromeBluetoothRemoteGattService_onBluetoothRemoteGattServiceAndroidDestruction(
      AttachCurrentThread(), j_service_);
}

base::android::ScopedJavaLocalRef<jobject>
BluetoothRemoteGattServiceAndroid::GetJavaObject() {
  return base::android::ScopedJavaLocalRef<jobject>(j_service_);
}

// static
BluetoothGattService::GattErrorCode
BluetoothRemoteGattServiceAndroid::GetGattErrorCode(int bluetooth_gatt_code) {
  DCHECK(bluetooth_gatt_code != 0) << "Only errors valid. 0 == GATT_SUCCESS.";

  // TODO(scheib) Create new BluetoothGattService::GattErrorCode enums for
  // android values not yet represented. http://crbug.com/548498
  switch (bluetooth_gatt_code) {  // android.bluetooth.BluetoothGatt values:
    case 0x00000101:              // GATT_FAILURE
      return GattErrorCode::kFailed;
    case 0x0000000d:  // GATT_INVALID_ATTRIBUTE_LENGTH
      return GattErrorCode::kInvalidLength;
    case 0x00000002:  // GATT_READ_NOT_PERMITTED
      return GattErrorCode::kNotPermitted;
    case 0x00000006:  // GATT_REQUEST_NOT_SUPPORTED
      return GattErrorCode::kNotSupported;
    case 0x00000003:  // GATT_WRITE_NOT_PERMITTED
      return GattErrorCode::kNotPermitted;
    default:
      DVLOG(1) << "Unhandled status: " << bluetooth_gatt_code;
      return BluetoothGattService::GattErrorCode::kUnknown;
  }
}

// static
int BluetoothRemoteGattServiceAndroid::GetAndroidErrorCode(
    BluetoothGattService::GattErrorCode error_code) {
  // TODO(scheib) Create new BluetoothGattService::GattErrorCode enums for
  // android values not yet represented. http://crbug.com/548498
  switch (error_code) {  // Return values from android.bluetooth.BluetoothGatt:
    case GattErrorCode::kUnknown:
      return 0x00000101;  // GATT_FAILURE. No good match.
    case GattErrorCode::kFailed:
      return 0x00000101;  // GATT_FAILURE
    case GattErrorCode::kInProgress:
      return 0x00000101;  // GATT_FAILURE. No good match.
    case GattErrorCode::kInvalidLength:
      return 0x0000000d;  // GATT_INVALID_ATTRIBUTE_LENGTH
    case GattErrorCode::kNotPermitted:
      // Can't distinguish between:
      // 0x00000002:  // GATT_READ_NOT_PERMITTED
      // 0x00000003:  // GATT_WRITE_NOT_PERMITTED
      return 0x00000101;  // GATT_FAILURE. No good match.
    case GattErrorCode::kNotAuthorized:
      return 0x00000101;  // GATT_FAILURE. No good match.
    case GattErrorCode::kNotPaired:
      return 0x00000101;  // GATT_FAILURE. No good match.
    case GattErrorCode::kNotSupported:
      return 0x00000006;  // GATT_REQUEST_NOT_SUPPORTED
  }
  DVLOG(1) << "Unhandled error_code: " << static_cast<int>(error_code);
  return 0x00000101;  // GATT_FAILURE. No good match.
}

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

device::BluetoothUUID BluetoothRemoteGattServiceAndroid::GetUUID() const {
  return device::BluetoothUUID(base::android::ConvertJavaStringToUTF8(
      Java_ChromeBluetoothRemoteGattService_getUUID(AttachCurrentThread(),
                                                    j_service_)));
}

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

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

std::vector<device::BluetoothRemoteGattCharacteristic*>
BluetoothRemoteGattServiceAndroid::GetCharacteristics() const {
  EnsureCharacteristicsCreated();
  return BluetoothRemoteGattService::GetCharacteristics();
}

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

device::BluetoothRemoteGattCharacteristic*
BluetoothRemoteGattServiceAndroid::GetCharacteristic(
    const std::string& identifier) const {
  EnsureCharacteristicsCreated();
  return BluetoothRemoteGattService::GetCharacteristic(identifier);
}

std::vector<BluetoothRemoteGattCharacteristic*>
BluetoothRemoteGattServiceAndroid::GetCharacteristicsByUUID(
    const BluetoothUUID& characteristic_uuid) const {
  EnsureCharacteristicsCreated();
  return BluetoothRemoteGattService::GetCharacteristicsByUUID(
      characteristic_uuid);
}

bool BluetoothRemoteGattServiceAndroid::IsDiscoveryComplete() const {
  // Not used on Android, because Android sends an event when service discovery
  // is complete for the entire device.
  NOTIMPLEMENTED();
  return true;
}

void BluetoothRemoteGattServiceAndroid::SetDiscoveryComplete(bool complete) {
  // Not used on Android, because Android sends an event when service discovery
  // is complete for the entire device.
  NOTIMPLEMENTED();
}

void BluetoothRemoteGattServiceAndroid::CreateGattRemoteCharacteristic(
    JNIEnv* env,
    const JavaParamRef<jobject>& caller,
    const JavaParamRef<jstring>& instance_id,
    const JavaParamRef<jobject>& /* BluetoothGattCharacteristicWrapper */
        bluetooth_gatt_characteristic_wrapper,
    const JavaParamRef<jobject>& /* ChromeBluetoothDevice */
        chrome_bluetooth_device) {
  std::string instance_id_string =
      base::android::ConvertJavaStringToUTF8(env, instance_id);

  DCHECK(!base::Contains(characteristics_, instance_id_string));
  AddCharacteristic(BluetoothRemoteGattCharacteristicAndroid::Create(
      adapter_, this, instance_id_string, bluetooth_gatt_characteristic_wrapper,
      chrome_bluetooth_device));
}

BluetoothRemoteGattServiceAndroid::BluetoothRemoteGattServiceAndroid(
    BluetoothAdapterAndroid* adapter,
    BluetoothDeviceAndroid* device,
    const std::string& instance_id)
    : adapter_(adapter), device_(device), instance_id_(instance_id) {}

void BluetoothRemoteGattServiceAndroid::EnsureCharacteristicsCreated() const {
  if (!characteristics_.empty())
    return;

  // Java call
  Java_ChromeBluetoothRemoteGattService_createCharacteristics(
      AttachCurrentThread(), j_service_);
}

}  // namespace device