Add bluetooth-core tests
Add BluetoothGattDescriptorTest, BluetoothGattCharacteristicTest
and BluetoothGattServiceTest
Test: ./gradlew bluetooth:bluetooth-core:connectAndroidTest --info --daemon
Change-Id: I6026dcbeadecf3f8adbb0208c2ef2612c72a1019
diff --git a/bluetooth/bluetooth-core/src/androidTest/java/androidx/bluetooth/core/BluetoothGattCharacteristicTest.kt b/bluetooth/bluetooth-core/src/androidTest/java/androidx/bluetooth/core/BluetoothGattCharacteristicTest.kt
new file mode 100644
index 0000000..dd93b64
--- /dev/null
+++ b/bluetooth/bluetooth-core/src/androidTest/java/androidx/bluetooth/core/BluetoothGattCharacteristicTest.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.bluetooth.core
+
+import android.os.Bundle
+import java.util.UUID
+import kotlin.random.Random
+import androidx.test.filters.MediumTest
+import org.junit.Assert
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@MediumTest
+@RunWith(JUnit4::class)
+class BluetoothGattCharacteristicTest {
+ companion object {
+ fun generateUUID(): UUID {
+ return UUID.randomUUID()
+ }
+
+ fun generatePermissions(): Int {
+ // Permission are bit from 1<<0 to 1<<8, but ignoring 1<<3
+ return Random.nextBits(20) and (BluetoothGattCharacteristic.PERMISSION_READ or
+ BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED or
+ BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED_MITM or
+ BluetoothGattCharacteristic.PERMISSION_WRITE or
+ BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED or
+ BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED_MITM or
+ BluetoothGattCharacteristic.PERMISSION_WRITE_SIGNED or
+ BluetoothGattCharacteristic.PERMISSION_WRITE_SIGNED_MITM)
+ }
+
+ fun generateProperties(): Int {
+ // Permission are bit from 1<<0 to 1<<7
+ return Random.nextBits(20) and (BluetoothGattCharacteristic.PROPERTY_BROADCAST or
+ BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS or
+ BluetoothGattCharacteristic.PROPERTY_INDICATE or
+ BluetoothGattCharacteristic.PROPERTY_NOTIFY or
+ BluetoothGattCharacteristic.PROPERTY_READ or
+ BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE or
+ BluetoothGattCharacteristic.PROPERTY_WRITE or
+ BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE)
+ }
+ }
+
+ @Test
+ fun constructorWithValues_createsInstanceCorrectly() {
+ repeat(5) {
+ val uuid = generateUUID()
+ val permissions = generatePermissions()
+ val properties = generateProperties()
+
+ val characteristic = BluetoothGattCharacteristic(uuid, properties, permissions)
+
+ Assert.assertEquals(permissions, characteristic.fwkCharacteristic.permissions)
+ Assert.assertEquals(properties, characteristic.fwkCharacteristic.properties)
+ Assert.assertEquals(uuid, characteristic.fwkCharacteristic.uuid)
+ Assert.assertEquals(permissions, characteristic.permissions)
+ Assert.assertEquals(properties, characteristic.properties)
+ Assert.assertEquals(uuid, characteristic.uuid)
+ Assert.assertEquals(null, characteristic.service)
+ }
+ }
+
+ @Test
+ fun bluetoothGattCharacteristicBundleable() {
+ repeat(5) {
+ val uuid = generateUUID()
+ val permissions = generatePermissions()
+ val properties = generateProperties()
+
+ val characteristic = BluetoothGattCharacteristic(uuid, properties, permissions)
+ characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
+
+ repeat(5) {
+ val descriptorUUID = BluetoothGattDescriptorTest.generateUUID()
+ val descriptorPermission = BluetoothGattDescriptorTest.generatePermissions()
+
+ val descriptor = BluetoothGattDescriptor(descriptorUUID, descriptorPermission)
+ characteristic.addDescriptor(descriptor)
+
+ Assert.assertEquals(characteristic, descriptor.characteristic)
+ }
+
+ val bundle: Bundle = characteristic.toBundle()
+ val newCharacteristic: BluetoothGattCharacteristic =
+ BluetoothGattCharacteristic.CREATOR.fromBundle(bundle)
+
+ Assert.assertEquals(newCharacteristic.permissions, characteristic.permissions)
+ Assert.assertEquals(newCharacteristic.instanceId, characteristic.instanceId)
+ Assert.assertEquals(newCharacteristic.uuid, characteristic.uuid)
+ Assert.assertEquals(newCharacteristic.properties, characteristic.properties)
+ Assert.assertEquals(newCharacteristic.writeType, characteristic.writeType)
+ Assert.assertEquals(newCharacteristic.descriptors.size, characteristic.descriptors.size)
+ newCharacteristic.descriptors.forEach {
+ val foundDescriptor = characteristic.getDescriptor(it.uuid)
+
+ Assert.assertEquals(foundDescriptor?.permissions, it.permissions)
+ Assert.assertEquals(foundDescriptor?.uuid, it.uuid)
+ Assert.assertEquals(foundDescriptor?.characteristic, characteristic)
+ Assert.assertEquals(it.characteristic, newCharacteristic)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/bluetooth/bluetooth-core/src/androidTest/java/androidx/bluetooth/core/BluetoothGattDescriptorTest.kt b/bluetooth/bluetooth-core/src/androidTest/java/androidx/bluetooth/core/BluetoothGattDescriptorTest.kt
new file mode 100644
index 0000000..6f317dd
--- /dev/null
+++ b/bluetooth/bluetooth-core/src/androidTest/java/androidx/bluetooth/core/BluetoothGattDescriptorTest.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.bluetooth.core
+
+import android.os.Bundle
+import androidx.test.filters.SmallTest
+
+import java.util.UUID
+import kotlin.random.Random
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class BluetoothGattDescriptorTest {
+
+ companion object {
+ fun generateUUID(): UUID {
+ return UUID.randomUUID()
+ }
+
+ fun generatePermissions(): Int {
+ // Permission are bit from 1<<0 to 1<<8, but ignoring 1<<3
+ return Random.nextBits(20) and (BluetoothGattDescriptor.PERMISSION_READ or
+ BluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED or
+ BluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED_MITM or
+ BluetoothGattDescriptor.PERMISSION_WRITE or
+ BluetoothGattDescriptor.PERMISSION_WRITE_ENCRYPTED or
+ BluetoothGattDescriptor.PERMISSION_WRITE_ENCRYPTED_MITM or
+ BluetoothGattDescriptor.PERMISSION_WRITE_SIGNED or
+ BluetoothGattDescriptor.PERMISSION_WRITE_SIGNED_MITM)
+ }
+ }
+
+ @Test
+ fun constructorWithValues_createsInstanceCorrectly() {
+ repeat(5) {
+ val uuid = generateUUID()
+ val permissions = generatePermissions()
+
+ val descriptor = BluetoothGattDescriptor(uuid, permissions)
+
+ assertEquals(permissions, descriptor.fwkDescriptor.permissions)
+ assertEquals(uuid, descriptor.fwkDescriptor.uuid)
+ assertEquals(permissions, descriptor.permissions)
+ assertEquals(uuid, descriptor.uuid)
+ assertEquals(null, descriptor.characteristic)
+ }
+ }
+
+ @Test
+ fun bluetoothGattDescriptorBundleable() {
+ repeat(5) {
+ val uuid = generateUUID()
+ val permissions = generatePermissions()
+ val descriptor = BluetoothGattDescriptor(uuid, permissions)
+ val bundle: Bundle = descriptor.toBundle()
+ val newDescriptor: BluetoothGattDescriptor =
+ BluetoothGattDescriptor.CREATOR.fromBundle(bundle)
+
+ assertEquals(newDescriptor.permissions, descriptor.permissions)
+ assertEquals(newDescriptor.uuid, descriptor.uuid)
+ }
+ }
+}
\ No newline at end of file
diff --git a/bluetooth/bluetooth-core/src/androidTest/java/androidx/bluetooth/core/BluetoothGattServiceTest.kt b/bluetooth/bluetooth-core/src/androidTest/java/androidx/bluetooth/core/BluetoothGattServiceTest.kt
new file mode 100644
index 0000000..b7bd14c
--- /dev/null
+++ b/bluetooth/bluetooth-core/src/androidTest/java/androidx/bluetooth/core/BluetoothGattServiceTest.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.bluetooth.core
+
+import android.os.Bundle
+import androidx.test.filters.MediumTest
+import java.util.UUID
+import kotlin.random.Random
+import org.junit.Assert
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@MediumTest
+@RunWith(JUnit4::class)
+class BluetoothGattServiceTest {
+ companion object {
+ fun generateUUID(): UUID {
+ return UUID.randomUUID()
+ }
+
+ fun generateType(): Int {
+ // Permission are bit from 1<<0 to 1<<8, but ignoring 1<<3
+ return Random.nextBits(1)
+ }
+ }
+
+ @Test
+ fun constructorWithValues_createsInstanceCorrectly() {
+ repeat(5) {
+ val uuid = generateUUID()
+ val type = generateType()
+
+ val service = BluetoothGattService(uuid, type)
+
+ Assert.assertEquals(uuid, service.uuid)
+ Assert.assertEquals(type, service.type)
+ Assert.assertEquals(uuid, service.fwkService.uuid)
+ Assert.assertEquals(type, service.fwkService.type)
+ Assert.assertEquals(0, service.includedServices.size)
+ Assert.assertEquals(0, service.characteristics.size)
+ }
+ }
+
+ @Test
+ fun bluetoothGattServiceBundleable() {
+ repeat(5) {
+
+ val serviceUuid = generateUUID()
+ val serviceType = generateType()
+
+ val service = BluetoothGattService(serviceUuid, serviceType)
+
+ repeat(5) {
+ val uuid = BluetoothGattCharacteristicTest.generateUUID()
+ val permissions = BluetoothGattCharacteristicTest.generatePermissions()
+ val properties = BluetoothGattCharacteristicTest.generateProperties()
+
+ val characteristic = BluetoothGattCharacteristic(uuid, properties, permissions)
+ characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
+
+ service.addCharacteristic(characteristic)
+
+ Assert.assertEquals(characteristic.service, service)
+ }
+
+ repeat(5) {
+ val uuid = generateUUID()
+ val type = generateType()
+
+ val includedService = BluetoothGattService(uuid, type)
+
+ service.addService(includedService)
+ }
+
+ val bundle: Bundle = service.toBundle()
+ val newService: BluetoothGattService =
+ BluetoothGattService.CREATOR.fromBundle(bundle)
+
+ Assert.assertEquals(newService.uuid, service.uuid)
+ Assert.assertEquals(newService.instanceId, service.instanceId)
+ Assert.assertEquals(newService.type, service.type)
+ Assert.assertEquals(newService.characteristics.size, service.characteristics.size)
+ Assert.assertEquals(newService.includedServices.size, service.includedServices.size)
+ newService.characteristics.forEach {
+ val foundCharacteristic = service.getCharacteristic(it.uuid)
+
+ Assert.assertEquals(foundCharacteristic?.permissions, it.permissions)
+ Assert.assertEquals(foundCharacteristic?.uuid, it.uuid)
+ Assert.assertEquals(foundCharacteristic?.instanceId, it.instanceId)
+ Assert.assertEquals(foundCharacteristic?.properties, it.properties)
+ Assert.assertEquals(foundCharacteristic?.writeType, it.writeType)
+ Assert.assertEquals(foundCharacteristic?.service, service)
+ Assert.assertEquals(it.service, newService)
+ }
+
+ newService.includedServices.forEach {
+ val foundService = service.getIncludedService(it.uuid)
+
+ Assert.assertEquals(foundService?.uuid, it.uuid)
+ Assert.assertEquals(foundService?.type, it.type)
+ Assert.assertEquals(foundService?.instanceId, it.instanceId)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/bluetooth/bluetooth-core/src/main/java/androidx/bluetooth/core/BluetoothGattCharacteristic.kt b/bluetooth/bluetooth-core/src/main/java/androidx/bluetooth/core/BluetoothGattCharacteristic.kt
index 9cce410..a82a182 100644
--- a/bluetooth/bluetooth-core/src/main/java/androidx/bluetooth/core/BluetoothGattCharacteristic.kt
+++ b/bluetooth/bluetooth-core/src/main/java/androidx/bluetooth/core/BluetoothGattCharacteristic.kt
@@ -66,7 +66,7 @@
const val FORMAT_UINT8 = FwkBluetoothGattCharacteristic.FORMAT_UINT8
/**
- * Characteristic proprty: Characteristic is broadcastable.
+ * Characteristic property: Characteristic is broadcastable.
*/
const val PROPERTY_BROADCAST =
FwkBluetoothGattCharacteristic.PROPERTY_BROADCAST
@@ -363,14 +363,6 @@
}
}
- init {
- fwkCharacteristic.descriptors.forEach {
- val descriptor = BluetoothGattDescriptor(it)
- _descriptors.add(descriptor)
- descriptor.characteristic = characteristic
- }
- }
-
override val uuid: UUID
get() = fwkCharacteristic.uuid
override val properties
@@ -388,6 +380,13 @@
override val descriptors
get() = _descriptors.toList()
override var service: BluetoothGattService? = null
+ init {
+ fwkCharacteristic.descriptors.forEach {
+ val descriptor = BluetoothGattDescriptor(it)
+ _descriptors.add(descriptor)
+ descriptor.characteristic = characteristic
+ }
+ }
override fun addDescriptor(
descriptor: BluetoothGattDescriptor,
diff --git a/bluetooth/bluetooth-core/src/main/java/androidx/bluetooth/core/BluetoothGattService.kt b/bluetooth/bluetooth-core/src/main/java/androidx/bluetooth/core/BluetoothGattService.kt
index 3ebc18b..c0042c3 100644
--- a/bluetooth/bluetooth-core/src/main/java/androidx/bluetooth/core/BluetoothGattService.kt
+++ b/bluetooth/bluetooth-core/src/main/java/androidx/bluetooth/core/BluetoothGattService.kt
@@ -34,12 +34,12 @@
/**
* Primary service
*/
- val SERVICE_TYPE_PRIMARY = FwkBluetoothGattService.SERVICE_TYPE_PRIMARY
+ const val SERVICE_TYPE_PRIMARY = FwkBluetoothGattService.SERVICE_TYPE_PRIMARY
/**
* Secondary service (included by primary services)
*/
- val SERVICE_TYPE_SECONDARY = FwkBluetoothGattService.SERVICE_TYPE_SECONDARY
+ const val SERVICE_TYPE_SECONDARY = FwkBluetoothGattService.SERVICE_TYPE_SECONDARY
/**
* A companion object to create [BluetoothGattService] from bundle
*/
@@ -193,7 +193,7 @@
private open class GattServiceImplApi21(
final override val fwkService: FwkBluetoothGattService,
- service: BluetoothGattService
+ private val service: BluetoothGattService
) : GattServiceImpl {
companion object {
@@ -301,6 +301,7 @@
override fun addCharacteristic(characteristic: BluetoothGattCharacteristic): Boolean {
return if (fwkService.addCharacteristic(characteristic.fwkCharacteristic)) {
_characteristics.add(characteristic)
+ characteristic.service = service
true
} else {
false
diff --git a/bluetooth/bluetooth-core/src/main/java/androidx/bluetooth/core/utils/Utils.kt b/bluetooth/bluetooth-core/src/main/java/androidx/bluetooth/core/utils/Utils.kt
index 2eb25fc..664275e 100644
--- a/bluetooth/bluetooth-core/src/main/java/androidx/bluetooth/core/utils/Utils.kt
+++ b/bluetooth/bluetooth-core/src/main/java/androidx/bluetooth/core/utils/Utils.kt
@@ -35,39 +35,33 @@
key: String,
clazz: Class<T>
): T? {
- val parcelable: T?
bundle.classLoader = clazz.classLoader
- try {
+ return try {
if (Build.VERSION.SDK_INT >= 33) {
- parcelable = bundle.getParcelable(key, clazz)
+ bundle.getParcelable(key, clazz)
} else {
- parcelable = bundle.getParcelable(key)
+ bundle.getParcelable(key)
}
} catch (e: Exception) {
- return null
+ null
}
- return parcelable
}
-
+ @SuppressLint("ClassVerificationFailure") // bundle.getParcelable(key, clazz)
@Suppress("DEPRECATION")
fun <T : Parcelable> getParcelableArrayListFromBundle(
bundle: Bundle,
key: String,
clazz: Class<T>
): List<T> {
- bundle.classLoader = clazz.classLoader
- if (Build.VERSION.SDK_INT >= 33) {
- // TODO: Return framework's getParcelableArrayList when SDK 33 is available
- // return bundle.getParcelableArrayList(key, clazz)
- TODO()
- } else {
- val parcelable: List<T>
- try {
- parcelable = bundle.getParcelableArrayList(key) ?: emptyList()
- } catch (e: Exception) {
- return emptyList()
+ return try {
+ bundle.classLoader = clazz.classLoader
+ if (Build.VERSION.SDK_INT >= 33) {
+ bundle.getParcelableArrayList(key, clazz) ?: emptyList()
+ } else {
+ bundle.getParcelableArrayList(key) ?: emptyList()
}
- return parcelable
+ } catch (e: Exception) {
+ emptyList()
}
}
}
\ No newline at end of file