text: // Copyright 2015 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_adapter_android.h"
  
  #include <memory>
  
  #include "base/android/jni_android.h"
  #include "base/android/jni_string.h"
  #include "base/sequenced_task_runner.h"
  #include "base/single_thread_task_runner.h"
  #include "base/threading/thread_task_runner_handle.h"
  #include "device/bluetooth/android/wrappers.h"
  #include "device/bluetooth/bluetooth_advertisement.h"
  #include "device/bluetooth/bluetooth_device_android.h"
  #include "device/bluetooth/bluetooth_discovery_session_outcome.h"
  #include "jni/ChromeBluetoothAdapter_jni.h"
  
  using base::android::AttachCurrentThread;
  using base::android::ConvertJavaStringToUTF8;
  
  namespace device {
  
  // static
  base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
      const InitCallback& init_callback) {
    return BluetoothAdapterAndroid::Create(
        BluetoothAdapterWrapper_CreateWithDefaultAdapter().obj());
  }
  
  // static
  base::WeakPtr<BluetoothAdapterAndroid> BluetoothAdapterAndroid::Create(
      jobject bluetooth_adapter_wrapper) {  // Java Type: bluetoothAdapterWrapper
    BluetoothAdapterAndroid* adapter = new BluetoothAdapterAndroid();
  
    adapter->j_adapter_.Reset(Java_ChromeBluetoothAdapter_create(
        AttachCurrentThread(), reinterpret_cast<intptr_t>(adapter),
        bluetooth_adapter_wrapper));
  
    return adapter->weak_ptr_factory_.GetWeakPtr();
  }
  
  // static
  bool BluetoothAdapterAndroid::RegisterJNI(JNIEnv* env) {
    return RegisterNativesImpl(env);  // Generated in BluetoothAdapter_jni.h
  }
  
  std::string BluetoothAdapterAndroid::GetAddress() const {
    return ConvertJavaStringToUTF8(Java_ChromeBluetoothAdapter_getAddress(
        AttachCurrentThread(), j_adapter_.obj()));
  }
  
  std::string BluetoothAdapterAndroid::GetName() const {
    return ConvertJavaStringToUTF8(Java_ChromeBluetoothAdapter_getName(
        AttachCurrentThread(), j_adapter_.obj()));
  }
  
  void BluetoothAdapterAndroid::SetName(const std::string& name,
                                        const base::Closure& callback,
                                        const ErrorCallback& error_callback) {
    NOTIMPLEMENTED();
  }
  
  bool BluetoothAdapterAndroid::IsInitialized() const {
    return true;
  }
  
  bool BluetoothAdapterAndroid::IsPresent() const {
    return Java_ChromeBluetoothAdapter_isPresent(AttachCurrentThread(),
                                                 j_adapter_.obj());
  }
  
  bool BluetoothAdapterAndroid::IsPowered() const {
    return Java_ChromeBluetoothAdapter_isPowered(AttachCurrentThread(),
                                                 j_adapter_.obj());
  }
  
  void BluetoothAdapterAndroid::SetPowered(bool powered,
                                           const base::Closure& callback,
                                           const ErrorCallback& error_callback) {
    if (Java_ChromeBluetoothAdapter_setPowered(AttachCurrentThread(),
                                               j_adapter_.obj(), powered)) {
      callback.Run();
    } else {
      error_callback.Run();
    }
  }
  
  bool BluetoothAdapterAndroid::IsDiscoverable() const {
    return Java_ChromeBluetoothAdapter_isDiscoverable(AttachCurrentThread(),
                                                      j_adapter_.obj());
  }
  
  void BluetoothAdapterAndroid::SetDiscoverable(
      bool discoverable,
      const base::Closure& callback,
      const ErrorCallback& error_callback) {
    NOTIMPLEMENTED();
  }
  
  bool BluetoothAdapterAndroid::IsDiscovering() const {
    return Java_ChromeBluetoothAdapter_isDiscovering(AttachCurrentThread(),
                                                     j_adapter_.obj());
  }
  
  BluetoothAdapter::UUIDList BluetoothAdapterAndroid::GetUUIDs() const {
    NOTIMPLEMENTED();
    return UUIDList();
  }
  
  void BluetoothAdapterAndroid::CreateRfcommService(
      const BluetoothUUID& uuid,
      const ServiceOptions& options,
      const CreateServiceCallback& callback,
      const CreateServiceErrorCallback& error_callback) {
    NOTIMPLEMENTED();
    error_callback.Run("Not Implemented");
  }
  
  void BluetoothAdapterAndroid::CreateL2capService(
      const BluetoothUUID& uuid,
      const ServiceOptions& options,
      const CreateServiceCallback& callback,
      const CreateServiceErrorCallback& error_callback) {
    NOTIMPLEMENTED();
    error_callback.Run("Not Implemented");
  }
  
  void BluetoothAdapterAndroid::RegisterAudioSink(
      const BluetoothAudioSink::Options& options,
      const AcquiredCallback& callback,
      const BluetoothAudioSink::ErrorCallback& error_callback) {
    error_callback.Run(BluetoothAudioSink::ERROR_UNSUPPORTED_PLATFORM);
  }
  
  void BluetoothAdapterAndroid::RegisterAdvertisement(
      std::unique_ptr<BluetoothAdvertisement::Data> advertisement_data,
      const CreateAdvertisementCallback& callback,
      const CreateAdvertisementErrorCallback& error_callback) {
    error_callback.Run(BluetoothAdvertisement::ERROR_UNSUPPORTED_PLATFORM);
  }
  
  BluetoothLocalGattService* BluetoothAdapterAndroid::GetGattService(
      const std::string& identifier) const {
    return nullptr;
  }
  
  void BluetoothAdapterAndroid::OnAdapterStateChanged(
      JNIEnv* env,
      const JavaParamRef<jobject>& caller,
      const bool powered) {
    NotifyAdapterStateChanged(powered);
  }
  
  void BluetoothAdapterAndroid::OnScanFailed(
      JNIEnv* env,
      const JavaParamRef<jobject>& caller) {
    MarkDiscoverySessionsAsInactive();
  }
  
  void BluetoothAdapterAndroid::CreateOrUpdateDeviceOnScan(
      JNIEnv* env,
      const JavaParamRef<jobject>& caller,
      const JavaParamRef<jstring>& address,
      const JavaParamRef<jobject>&
          bluetooth_device_wrapper,  // Java Type: bluetoothDeviceWrapper
      const JavaParamRef<jobject>&
          advertised_uuids) {  // Java Type: List<ParcelUuid>
    std::string device_address = ConvertJavaStringToUTF8(env, address);
    DevicesMap::const_iterator iter = devices_.find(device_address);
  
    if (iter == devices_.end()) {
      // New device.
      BluetoothDeviceAndroid* device_android =
          BluetoothDeviceAndroid::Create(this, bluetooth_device_wrapper);
      device_android->UpdateAdvertisedUUIDs(advertised_uuids);
      devices_.add(device_address,
                   std::unique_ptr<BluetoothDevice>(device_android));
      FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
                        DeviceAdded(this, device_android));
    } else {
      // Existing device.
      BluetoothDeviceAndroid* device_android =
          static_cast<BluetoothDeviceAndroid*>(iter->second);
      if (device_android->UpdateAdvertisedUUIDs(advertised_uuids)) {
        FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
                          DeviceChanged(this, device_android));
      }
    }
  }
  
  BluetoothAdapterAndroid::BluetoothAdapterAndroid() : weak_ptr_factory_(this) {
  }
  
  BluetoothAdapterAndroid::~BluetoothAdapterAndroid() {
    Java_ChromeBluetoothAdapter_onBluetoothAdapterAndroidDestruction(
        AttachCurrentThread(), j_adapter_.obj());
  }
  
  void BluetoothAdapterAndroid::AddDiscoverySession(
      BluetoothDiscoveryFilter* discovery_filter,
      const base::Closure& callback,
      const DiscoverySessionErrorCallback& error_callback) {
    // TODO(scheib): Support filters crbug.com/490401
    if (Java_ChromeBluetoothAdapter_addDiscoverySession(AttachCurrentThread(),
                                                        j_adapter_.obj())) {
      callback.Run();
    } else {
      // TODO(scheib): Eventually wire the SCAN_FAILED result through to here.
      error_callback.Run(UMABluetoothDiscoverySessionOutcome::UNKNOWN);
    }
  }
  
  void BluetoothAdapterAndroid::RemoveDiscoverySession(
      BluetoothDiscoveryFilter* discovery_filter,
      const base::Closure& callback,
      const DiscoverySessionErrorCallback& error_callback) {
    if (Java_ChromeBluetoothAdapter_removeDiscoverySession(AttachCurrentThread(),
                                                           j_adapter_.obj())) {
      callback.Run();
    } else {
      // TODO(scheib): Eventually wire the SCAN_FAILED result through to here.
      error_callback.Run(UMABluetoothDiscoverySessionOutcome::UNKNOWN);
    }
  }
  
  void BluetoothAdapterAndroid::SetDiscoveryFilter(
      std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
      const base::Closure& callback,
      const DiscoverySessionErrorCallback& error_callback) {
    // TODO(scheib): Support filters crbug.com/490401
    NOTIMPLEMENTED();
    error_callback.Run(UMABluetoothDiscoverySessionOutcome::NOT_IMPLEMENTED);
  }
  
  void BluetoothAdapterAndroid::RemovePairingDelegateInternal(
      device::BluetoothDevice::PairingDelegate* pairing_delegate) {
  }
  
  }  // namespace device
  