1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.car.obd2.connections;
18 
19 import android.bluetooth.BluetoothAdapter;
20 import android.bluetooth.BluetoothDevice;
21 import android.bluetooth.BluetoothSocket;
22 import android.util.Log;
23 import com.android.car.obd2.Obd2Connection;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.OutputStream;
27 import java.util.Objects;
28 import java.util.UUID;
29 
30 public class BluetoothConnection implements Obd2Connection.UnderlyingTransport {
31 
32     /**
33      * This is the well-known UUID for the Bluetooth SPP (Serial Port Profile)
34      */
35     private static final UUID SERIAL_PORT_PROFILE = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
36 
37     private final BluetoothDevice mDevice;
38     private BluetoothSocket mSocket = null;
39 
40     public static final String TAG = BluetoothConnection.class.getSimpleName();
41 
BluetoothConnection(String bluetoothAddress)42     public BluetoothConnection(String bluetoothAddress) {
43         this(BluetoothAdapter.getDefaultAdapter().getRemoteDevice(bluetoothAddress));
44     }
45 
BluetoothConnection(BluetoothDevice device)46     public BluetoothConnection(BluetoothDevice device) {
47         mDevice = Objects.requireNonNull(device);
48         connect();
49     }
50 
51     @Override
getAddress()52     public String getAddress() {
53         return mDevice.getAddress();
54     }
55 
56     /**
57      * Establish an RFCOMM connection to the remote device.
58      *
59      * Assumes there is no existing connection.
60      *
61      * This method may take time to return (or even not return in pathological cases).
62      * It is a good idea to wrap it in some kind of Promise-like object.
63      *
64      * @return true if it could connect, false otherwise
65      */
connect()66     private boolean connect() {
67         try {
68             mSocket = mDevice.createRfcommSocketToServiceRecord(SERIAL_PORT_PROFILE);
69             mSocket.connect();
70         } catch (IOException e) {
71             Log.w(TAG, "BluetoothConnection couldn't be established due to an exception: " + e);
72             mSocket = null;
73             return false;
74         }
75         return mSocket.isConnected();
76     }
77 
78     @Override
isConnected()79     public boolean isConnected() {
80         return mSocket != null && mSocket.isConnected();
81     }
82 
close()83     private void close() {
84         if (isConnected()) {
85             try {
86                 mSocket.close();
87             } catch (IOException e) {
88                 // we are letting go of the connection anyway, so log and continue
89                 Log.w(TAG, "IOException during BluetoothSocket close(): " + e);
90             } finally {
91                 mSocket = null;
92             }
93         }
94     }
95 
96     @Override
reconnect()97     public boolean reconnect() {
98         close();
99         return connect();
100     }
101 
102     @Override
getInputStream()103     public InputStream getInputStream() {
104         if (isConnected()) {
105             try {
106                 return mSocket.getInputStream();
107             } catch (IOException e) {
108                 Log.w(TAG, "failed to get Bluetooth input stream: " + e);
109             }
110         }
111         return null;
112     }
113 
114     @Override
getOutputStream()115     public OutputStream getOutputStream() {
116         if (isConnected()) {
117             try {
118                 return mSocket.getOutputStream();
119             } catch (IOException e) {
120                 Log.w(TAG, "failed to get Bluetooth output stream: " + e);
121             }
122         }
123         return null;
124     }
125 }
126