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);
+ }
+}