Convert CarBleManager to Java
Bug: 143651521
Test: Unit tests pass and association succeeds
Change-Id: I171ab0cf9131378c0c4f054354192f752e02cb01
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/ble/CarBleManager.java b/connected-device-lib/src/com/android/car/connecteddevice/ble/CarBleManager.java
new file mode 100644
index 0000000..d649d10
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/ble/CarBleManager.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2019 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 com.android.car.connecteddevice.ble;
+
+import static com.android.car.connecteddevice.util.SafeLog.logd;
+import static com.android.car.connecteddevice.util.SafeLog.logw;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+
+import com.android.car.connecteddevice.storage.ConnectedDeviceStorage;
+import com.android.car.connecteddevice.util.ThreadSafeCallbacks;
+
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.Executor;
+
+/**
+ * Generic BLE manager for a car that keeps track of connected devices and their associated
+ * callbacks.
+ */
+public abstract class CarBleManager {
+
+ private static final String TAG = "CarBleManager";
+
+ final ConnectedDeviceStorage mStorage;
+
+ final CopyOnWriteArraySet<BleDevice> mConnectedDevices = new CopyOnWriteArraySet<>();
+
+ final ThreadSafeCallbacks<Callback> mCallbacks = new ThreadSafeCallbacks<>();
+
+ protected CarBleManager(@NonNull ConnectedDeviceStorage connectedDeviceStorage) {
+ mStorage = connectedDeviceStorage;
+ }
+
+ /**
+ * Initialize and start the manager.
+ */
+ public void start() {
+ }
+
+ /**
+ * Stop the manager and clean up.
+ */
+ public void stop() {
+ for (BleDevice device : mConnectedDevices) {
+ if (device.mGatt != null) {
+ device.mGatt.close();
+ }
+ }
+ mConnectedDevices.clear();
+ mCallbacks.clear();
+ }
+
+ /**
+ * Register a {@link Callback} to be notified on the {@link Executor}.
+ */
+ public void registerCallback(@NonNull Callback callback, @NonNull Executor executor) {
+ mCallbacks.add(callback, executor);
+ }
+
+ /**
+ * Unregister a callback.
+ *
+ * @param callback The {@link Callback} to unregister.
+ */
+ public void unregisterCallback(@NonNull Callback callback) {
+ mCallbacks.remove(callback);
+ }
+
+ /**
+ * Send a message to a connected device.
+ *
+ * @param deviceId Id of connected device.
+ * @param message {@link DeviceMessage} to send.
+ */
+ public void sendMessage(@NonNull String deviceId, @NonNull DeviceMessage message) {
+ BleDevice device = getConnectedDevice(deviceId);
+ if (device == null) {
+ logw(TAG, "Attempted to send message to unknown device $deviceId. Ignored.");
+ return;
+ }
+
+ sendMessage(device, message);
+ }
+
+ /**
+ * Send a message to a connected device.
+ *
+ * @param device The connected {@link BleDevice}.
+ * @param message {@link DeviceMessage} to send.
+ */
+ public void sendMessage(@NonNull BleDevice device, @NonNull DeviceMessage message) {
+ String deviceId = device.mDeviceId;
+ if (deviceId == null) {
+ deviceId = "Unidentified device";
+ }
+
+ logd(TAG, "Writing " + message.getMessage().length + " bytes to " + deviceId + ".");
+
+
+ if (message.isMessageEncrypted()) {
+ device.mSecureChannel.sendEncryptedMessage(message);
+ } else {
+ device.mSecureChannel.getStream().writeMessage(message);
+ }
+ }
+
+ /**
+ * Get the {@link BleDevice} with matching {@link BluetoothGatt} if available. Returns
+ * {@code null} if no matches are found.
+ */
+ @Nullable
+ BleDevice getConnectedDevice(@NonNull BluetoothGatt gatt) {
+ for (BleDevice device : mConnectedDevices) {
+ if (device.mGatt == gatt) {
+ return device;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the {@link BleDevice} with matching {@link BluetoothDevice} if available. Returns
+ * {@code null} if no matches are found.
+ */
+ @Nullable
+ BleDevice getConnectedDevice(@NonNull BluetoothDevice device) {
+ for (BleDevice connectedDevice : mConnectedDevices) {
+ if (device.equals(connectedDevice.mDevice)) {
+ return connectedDevice;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the {@link BleDevice} with matching device id if available. Returns {@code null} if
+ * no matches are found.
+ */
+ @Nullable
+ BleDevice getConnectedDevice(@NonNull String deviceId) {
+ for (BleDevice device : mConnectedDevices) {
+ if (deviceId.equals(device.mDeviceId)) {
+ return device;
+ }
+ }
+
+ return null;
+ }
+
+ /** Add the {@link BleDevice} that has connected. */
+ void addConnectedDevice(@NonNull BleDevice device) {
+ mConnectedDevices.add(device);
+ }
+
+ /** Return the number of devices currently connected. */
+ int getConnectedDevicesCount() {
+ return mConnectedDevices.size();
+ }
+
+ /** Remove [@link BleDevice} that has been disconnected. */
+ void removeConnectedDevice(@NonNull BleDevice device) {
+ mConnectedDevices.remove(device);
+ }
+
+ /** State for a connected device. */
+ enum BleDeviceState {
+ CONNECTING,
+ PENDING_VERIFICATION,
+ CONNECTED,
+ UNKNOWN
+ }
+
+ /**
+ * Container class to hold information about a connected device.
+ */
+ static class BleDevice {
+
+ BluetoothDevice mDevice;
+ BluetoothGatt mGatt;
+ BleDeviceState mState;
+ String mDeviceId;
+ SecureBleChannel mSecureChannel;
+
+ BleDevice(@NonNull BluetoothDevice device, @Nullable BluetoothGatt gatt) {
+ mDevice = device;
+ mGatt = gatt;
+ mState = BleDeviceState.UNKNOWN;
+ }
+ }
+
+ /**
+ * Callback for triggered events from {@link CarBleManager}.
+ */
+ public interface Callback {
+ /**
+ * Triggered when device is connected and device id retrieved. Device is now ready to
+ * receive messages.
+ *
+ * @param deviceId Id of device that has connected.
+ */
+ void onDeviceConnected(@NonNull String deviceId);
+
+ /**
+ * Triggered when device is disconnected.
+ *
+ * @param deviceId Id of device that has disconnected.
+ */
+ void onDeviceDisconnected(@NonNull String deviceId);
+
+ /**
+ * Triggered when device has established encryption for secure communication.
+ *
+ * @param deviceId Id of device that has established encryption.
+ */
+ void onSecureChannelEstablished(@NonNull String deviceId);
+
+ /**
+ * Triggered when a new message is received.
+ *
+ * @param deviceId Id of the device that sent the message.
+ * @param message {@link DeviceMessage} received.
+ */
+ void onMessageReceived(@NonNull String deviceId, @NonNull DeviceMessage message);
+
+ /**
+ * Triggered when an error when establishing the secure channel.
+ *
+ * @param deviceId Id of the device that experienced the error.
+ */
+ void onSecureChannelError(@NonNull String deviceId);
+ }
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/ble/CarBleManager.kt b/connected-device-lib/src/com/android/car/connecteddevice/ble/CarBleManager.kt
deleted file mode 100644
index 6dbc208..0000000
--- a/connected-device-lib/src/com/android/car/connecteddevice/ble/CarBleManager.kt
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2019 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 com.android.car.connecteddevice.ble
-
-import android.bluetooth.BluetoothDevice
-import android.bluetooth.BluetoothGatt
-import com.android.car.connecteddevice.storage.ConnectedDeviceStorage
-import com.android.car.connecteddevice.util.ThreadSafeCallbacksKt
-import com.android.car.connecteddevice.util.logd
-import com.android.car.connecteddevice.util.logw
-import java.util.concurrent.CopyOnWriteArraySet
-import java.util.concurrent.Executor
-
-private const val TAG = "CarBleManager"
-
-/**
- * Generic BLE manager for a car that keeps track of connected devices and their associated
- * callbacks.
- *
- * @param connectedDeviceStorage Shared [ConnectedDeviceStorage] for companion features.
- */
-internal abstract class CarBleManager(
- private val connectedDeviceStorage: ConnectedDeviceStorage
-) {
-
- protected val connectedDevices = CopyOnWriteArraySet<BleDevice>()
-
- protected val callbacks = ThreadSafeCallbacksKt<Callback>()
-
- open fun start() {
- }
-
- open fun stop() {
- connectedDevices.forEach { it.gatt?.close() }
- connectedDevices.clear()
- callbacks.clear()
- }
-
- /**
- * Register a [callback] to be notified on the [executor].
- */
- fun registerCallback(callback: Callback, executor: Executor) {
- callbacks.add(callback, executor)
- }
-
- /**
- * Unregister a callback
- *
- * @param callback The [Callback] to unregister.
- */
- fun unregisterCallback(callback: Callback) {
- callbacks.remove(callback)
- }
-
- /**
- * Send a message to a connected device.
- *
- * @param deviceId Id of connected device.
- * @param message [DeviceMessage] to send.
- */
- fun sendMessage(deviceId: String, message: DeviceMessage) {
- getConnectedDevice(deviceId)?.run {
- sendMessage(this, message)
- } ?: logw(TAG, "Attempted to send message to unknown device $deviceId. Ignored")
- }
-
- /**
- * Send a message to a connected device.
- *
- * @param bleDevice The connected [BleDevice].
- * @param message [DeviceMessage] to send.
- */
- protected fun sendMessage(bleDevice: BleDevice, message: DeviceMessage) {
- logd(
- TAG,
- "Writing ${message.message.size} bytes to " +
- "${bleDevice.deviceId ?: "Unidentified device"}."
- )
-
- if (message.isMessageEncrypted) {
- bleDevice.secureChannel?.sendEncryptedMessage(message)
- } else {
- bleDevice.secureChannel?.stream?.writeMessage(message)
- }
- }
-
- /**
- * Get the [BleDevice] with matching [gatt] if available. Returns `null` if no matches
- * found.
- */
- protected fun getConnectedDevice(gatt: BluetoothGatt): BleDevice? {
- return connectedDevices.firstOrNull { it.gatt == gatt }
- }
-
- /**
- * Get the [BleDevice] with matching [device] if available. Returns `null` if no
- * matches found.
- */
- protected fun getConnectedDevice(device: BluetoothDevice): BleDevice? {
- return connectedDevices.firstOrNull { it.device == device }
- }
-
- /**
- * Get the [BleDevice] with matching [deviceId] if available. Returns `null` if no matches
- * found.
- */
- protected fun getConnectedDevice(deviceId: String): BleDevice? {
- return connectedDevices.firstOrNull { it.deviceId == deviceId }
- }
-
- /** Add the [bleDevice] that has connected. */
- protected fun addConnectedDevice(bleDevice: BleDevice) {
- connectedDevices.add(bleDevice)
- }
-
- /** Return the number of devices currently connected. */
- protected fun connectedDevicesCount(): Int {
- return connectedDevices.count()
- }
-
- /** Remove [bleDevice] that has been disconnected. */
- protected fun removeConnectedDevice(bleDevice: BleDevice) {
- connectedDevices.remove(bleDevice)
- }
-
- /**
- * Container class to hold information about a connected device.
- *
- * @param device The [BluetoothDevice] from the connection.
- * @param gatt The [BluetoothGatt] from the connection. Only applicable for central connections.
- */
- protected data class BleDevice(
- val device: BluetoothDevice,
- val gatt: BluetoothGatt?
- ) {
- var state: BleDeviceState = BleDeviceState.UNKNOWN
- var deviceId: String? = null
- var secureChannel: SecureBleChannel? = null
- }
-
- /** State for a connected device. */
- protected enum class BleDeviceState {
- CONNECTING,
- PENDING_VERIFICATION,
- CONNECTED,
- UNKNOWN
- }
-
- /**
- * Callback for triggered events from [CarBleManager].
- */
- interface Callback {
-
- /**
- * Triggered when device is connected and device id retrieved. Device is now ready to
- * receive messages.
- *
- * @param deviceId Id of device that has connected.
- */
- fun onDeviceConnected(deviceId: String)
-
- /**
- * Triggered when device is disconnected.
- *
- * @param deviceId Id of device that has disconnected.
- */
- fun onDeviceDisconnected(deviceId: String)
-
- /**
- * Triggered when device has established encryption for secure communication.
- *
- * @param deviceId Id of device that has established encryption.
- */
- fun onSecureChannelEstablished(deviceId: String)
-
- /**
- * Triggered when a new message is received.
- *
- * @param deviceId Id of the device that sent the message.
- * @param message [DeviceMessage] received.
- */
- fun onMessageReceived(deviceId: String, message: DeviceMessage)
-
- /**
- * Triggered when an error when establishing the secure channel.
- *
- * @param deviceId Id of the device that experienced the error.
- */
- fun onSecureChannelError(deviceId: String)
- }
-}