/* * Copyright (C) 2017 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.obd2.connections; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.util.Log; import com.android.car.obd2.Obd2Connection; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Objects; import java.util.UUID; public class BluetoothConnection implements Obd2Connection.UnderlyingTransport { /** * This is the well-known UUID for the Bluetooth SPP (Serial Port Profile) */ private static final UUID SERIAL_PORT_PROFILE = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); private final BluetoothDevice mDevice; private BluetoothSocket mSocket = null; public static final String TAG = BluetoothConnection.class.getSimpleName(); public BluetoothConnection(String bluetoothAddress) { this(BluetoothAdapter.getDefaultAdapter().getRemoteDevice(bluetoothAddress)); } public BluetoothConnection(BluetoothDevice device) { mDevice = Objects.requireNonNull(device); connect(); } @Override public String getAddress() { return mDevice.getAddress(); } /** * Establish an RFCOMM connection to the remote device. * * Assumes there is no existing connection. * * This method may take time to return (or even not return in pathological cases). * It is a good idea to wrap it in some kind of Promise-like object. * * @return true if it could connect, false otherwise */ private boolean connect() { try { mSocket = mDevice.createRfcommSocketToServiceRecord(SERIAL_PORT_PROFILE); mSocket.connect(); } catch (IOException e) { Log.w(TAG, "BluetoothConnection couldn't be established due to an exception: " + e); mSocket = null; return false; } return mSocket.isConnected(); } @Override public boolean isConnected() { return mSocket != null && mSocket.isConnected(); } private void close() { if (isConnected()) { try { mSocket.close(); } catch (IOException e) { // we are letting go of the connection anyway, so log and continue Log.w(TAG, "IOException during BluetoothSocket close(): " + e); } finally { mSocket = null; } } } @Override public boolean reconnect() { close(); return connect(); } @Override public InputStream getInputStream() { if (isConnected()) { try { return mSocket.getInputStream(); } catch (IOException e) { Log.w(TAG, "failed to get Bluetooth input stream: " + e); } } return null; } @Override public OutputStream getOutputStream() { if (isConnected()) { try { return mSocket.getOutputStream(); } catch (IOException e) { Log.w(TAG, "failed to get Bluetooth output stream: " + e); } } return null; } }