diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/BluetoothAdapter.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/BluetoothAdapter.java index 07f6349ddaaa8c..3c8b26521f6008 100644 --- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/BluetoothAdapter.java +++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/BluetoothAdapter.java @@ -4,7 +4,9 @@ package org.chromium.device.bluetooth; +import android.Manifest; import android.content.Context; +import android.content.ContextWrapper; import android.content.pm.PackageManager; import org.chromium.base.CalledByNative; @@ -20,6 +22,7 @@ final class BluetoothAdapter { private static final String TAG = Log.makeTag("Bluetooth"); private final boolean mHasBluetoothPermission; + private android.bluetooth.BluetoothAdapter mAdapter; @CalledByNative private static BluetoothAdapter create(Context context) { @@ -27,16 +30,78 @@ private static BluetoothAdapter create(Context context) { } @CalledByNative - private boolean hasBluetoothPermission() { - return mHasBluetoothPermission; + private static BluetoothAdapter createWithoutPermissionForTesting(Context context) { + Context contextWithoutPermission = new ContextWrapper(context) { + @Override + public int checkCallingOrSelfPermission(String permission) { + return PackageManager.PERMISSION_DENIED; + } + }; + return new BluetoothAdapter(contextWithoutPermission); } + // Constructs a BluetoothAdapter. private BluetoothAdapter(Context context) { mHasBluetoothPermission = - context.checkCallingOrSelfPermission(android.Manifest.permission.BLUETOOTH) - == PackageManager.PERMISSION_GRANTED; + context.checkCallingOrSelfPermission(Manifest.permission.BLUETOOTH) + == PackageManager.PERMISSION_GRANTED + && context.checkCallingOrSelfPermission(Manifest.permission.BLUETOOTH_ADMIN) + == PackageManager.PERMISSION_GRANTED; if (!mHasBluetoothPermission) { - Log.w(TAG, "Can not use bluetooth API, requires BLUETOOTH permission."); + Log.w(TAG, + "Bluetooth API disabled; BLUETOOTH and BLUETOOTH_ADMIN permissions required."); + return; } + + mAdapter = android.bluetooth.BluetoothAdapter.getDefaultAdapter(); + if (mAdapter == null) Log.i(TAG, "No adapter found."); + } + + @CalledByNative + private boolean hasBluetoothPermission() { + return mHasBluetoothPermission; + } + + // --------------------------------------------------------------------------------------------- + // BluetoothAdapterAndroid.h interface: + + @CalledByNative + private String getAddress() { + if (isPresent()) { + return mAdapter.getAddress(); + } else { + return ""; + } + } + + @CalledByNative + private String getName() { + if (isPresent()) { + return mAdapter.getName(); + } else { + return ""; + } + } + + @CalledByNative + private boolean isPresent() { + return mAdapter != null; + } + + @CalledByNative + private boolean isPowered() { + return isPresent() && mAdapter.isEnabled(); + } + + @CalledByNative + private boolean isDiscoverable() { + return isPresent() + && mAdapter.getScanMode() + == android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; + } + + @CalledByNative + private boolean isDiscovering() { + return isPresent() && mAdapter.isDiscovering(); } } diff --git a/device/bluetooth/bluetooth_adapter_android.cc b/device/bluetooth/bluetooth_adapter_android.cc index 0d4f1408f5bddf..0b8bea30de4283 100644 --- a/device/bluetooth/bluetooth_adapter_android.cc +++ b/device/bluetooth/bluetooth_adapter_android.cc @@ -5,6 +5,7 @@ #include "device/bluetooth/bluetooth_adapter_android.h" #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/thread_task_runner_handle.h" @@ -12,6 +13,7 @@ #include "jni/BluetoothAdapter_jni.h" using base::android::AttachCurrentThread; +using base::android::ConvertJavaStringToUTF8; namespace device { @@ -25,6 +27,17 @@ base::WeakPtr BluetoothAdapter::CreateAdapter( base::WeakPtr BluetoothAdapterAndroid::CreateAdapter() { BluetoothAdapterAndroid* adapter = new BluetoothAdapterAndroid(); + adapter->j_bluetooth_adapter_.Reset(Java_BluetoothAdapter_create( + AttachCurrentThread(), base::android::GetApplicationContext())); + return adapter->weak_ptr_factory_.GetWeakPtr(); +} + +base::WeakPtr +BluetoothAdapterAndroid::CreateAdapterWithoutPermissionForTesting() { + BluetoothAdapterAndroid* adapter = new BluetoothAdapterAndroid(); + adapter->j_bluetooth_adapter_.Reset( + Java_BluetoothAdapter_createWithoutPermissionForTesting( + AttachCurrentThread(), base::android::GetApplicationContext())); return adapter->weak_ptr_factory_.GetWeakPtr(); } @@ -39,11 +52,13 @@ bool BluetoothAdapterAndroid::HasBluetoothPermission() const { } std::string BluetoothAdapterAndroid::GetAddress() const { - return address_; + return ConvertJavaStringToUTF8(Java_BluetoothAdapter_getAddress( + AttachCurrentThread(), j_bluetooth_adapter_.obj())); } std::string BluetoothAdapterAndroid::GetName() const { - return name_; + return ConvertJavaStringToUTF8(Java_BluetoothAdapter_getName( + AttachCurrentThread(), j_bluetooth_adapter_.obj())); } void BluetoothAdapterAndroid::SetName(const std::string& name, @@ -58,13 +73,13 @@ bool BluetoothAdapterAndroid::IsInitialized() const { } bool BluetoothAdapterAndroid::IsPresent() const { - NOTIMPLEMENTED(); - return false; + return Java_BluetoothAdapter_isPresent(AttachCurrentThread(), + j_bluetooth_adapter_.obj()); } bool BluetoothAdapterAndroid::IsPowered() const { - NOTIMPLEMENTED(); - return false; + return Java_BluetoothAdapter_isPowered(AttachCurrentThread(), + j_bluetooth_adapter_.obj()); } void BluetoothAdapterAndroid::SetPowered(bool powered, @@ -74,8 +89,8 @@ void BluetoothAdapterAndroid::SetPowered(bool powered, } bool BluetoothAdapterAndroid::IsDiscoverable() const { - NOTIMPLEMENTED(); - return false; + return Java_BluetoothAdapter_isDiscoverable(AttachCurrentThread(), + j_bluetooth_adapter_.obj()); } void BluetoothAdapterAndroid::SetDiscoverable( @@ -86,8 +101,8 @@ void BluetoothAdapterAndroid::SetDiscoverable( } bool BluetoothAdapterAndroid::IsDiscovering() const { - NOTIMPLEMENTED(); - return false; + return Java_BluetoothAdapter_isDiscovering(AttachCurrentThread(), + j_bluetooth_adapter_.obj()); } void BluetoothAdapterAndroid::CreateRfcommService( @@ -123,8 +138,6 @@ void BluetoothAdapterAndroid::RegisterAdvertisement( } BluetoothAdapterAndroid::BluetoothAdapterAndroid() : weak_ptr_factory_(this) { - j_bluetooth_adapter_.Reset(Java_BluetoothAdapter_create( - AttachCurrentThread(), base::android::GetApplicationContext())); } BluetoothAdapterAndroid::~BluetoothAdapterAndroid() { diff --git a/device/bluetooth/bluetooth_adapter_android.h b/device/bluetooth/bluetooth_adapter_android.h index cfb9d31733b719..d458bb5659cc2a 100644 --- a/device/bluetooth/bluetooth_adapter_android.h +++ b/device/bluetooth/bluetooth_adapter_android.h @@ -23,6 +23,10 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterAndroid final // Create a BluetoothAdapterAndroid instance. static base::WeakPtr CreateAdapter(); + // Create a BluetoothAdapterAndroid instance without Bluetooth permission. + static base::WeakPtr + CreateAdapterWithoutPermissionForTesting(); + // Register C++ methods exposed to Java using JNI. static bool RegisterJNI(JNIEnv* env); diff --git a/device/bluetooth/bluetooth_adapter_android_unittest.cc b/device/bluetooth/bluetooth_adapter_android_unittest.cc index c4d5252e339c7a..1df32a2ecf6784 100644 --- a/device/bluetooth/bluetooth_adapter_android_unittest.cc +++ b/device/bluetooth/bluetooth_adapter_android_unittest.cc @@ -10,16 +10,45 @@ namespace device { class BluetoothAdapterAndroidTest : public testing::Test { protected: - BluetoothAdapterAndroidTest() { + void InitWithPermission() { adapter_ = BluetoothAdapterAndroid::CreateAdapter().get(); } + void InitWithoutPermission() { + adapter_ = + BluetoothAdapterAndroid::CreateAdapterWithoutPermissionForTesting() + .get(); + } + scoped_refptr adapter_; }; TEST_F(BluetoothAdapterAndroidTest, Construct) { + InitWithPermission(); + ASSERT_TRUE(adapter_.get()); + EXPECT_TRUE(adapter_->HasBluetoothPermission()); + if (!adapter_->IsPresent()) { + LOG(WARNING) << "Bluetooth adapter not present; skipping unit test."; + return; + } + EXPECT_GT(adapter_->GetAddress().length(), 0u); + EXPECT_GT(adapter_->GetName().length(), 0u); + EXPECT_TRUE(adapter_->IsPresent()); + EXPECT_TRUE(adapter_->IsPowered()); + EXPECT_FALSE(adapter_->IsDiscoverable()); + EXPECT_FALSE(adapter_->IsDiscovering()); +} + +TEST_F(BluetoothAdapterAndroidTest, ConstructNoPermision) { + InitWithoutPermission(); ASSERT_TRUE(adapter_.get()); EXPECT_FALSE(adapter_->HasBluetoothPermission()); + EXPECT_EQ(adapter_->GetAddress().length(), 0u); + EXPECT_EQ(adapter_->GetName().length(), 0u); + EXPECT_FALSE(adapter_->IsPresent()); + EXPECT_FALSE(adapter_->IsPowered()); + EXPECT_FALSE(adapter_->IsDiscoverable()); + EXPECT_FALSE(adapter_->IsDiscovering()); } } // namespace device diff --git a/testing/android/native_test/java/AndroidManifest.xml b/testing/android/native_test/java/AndroidManifest.xml index a92fb5fce5d5ed..37cc82dc01e6cb 100644 --- a/testing/android/native_test/java/AndroidManifest.xml +++ b/testing/android/native_test/java/AndroidManifest.xml @@ -11,7 +11,8 @@ found in the LICENSE file. android:versionName="1.0"> - + +