Import cleanup
[fw/altos] / altosdroid / app / src / main / java / org / altusmetrum / AltosDroid / AltosBluetooth.java
1 /*
2  * Copyright © 2011 Keith Packard <keithp@keithp.com>
3  * Copyright © 2012 Mike Beattie <mike@ethernal.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
18  */
19
20 package org.altusmetrum.AltosDroid;
21
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.OutputStream;
25 import java.util.UUID;
26
27 import android.bluetooth.BluetoothAdapter;
28 import android.bluetooth.BluetoothDevice;
29 import android.bluetooth.BluetoothSocket;
30 import android.os.Handler;
31
32 public class AltosBluetooth extends AltosDroidLink {
33
34         private ConnectThread    connect_thread = null;
35
36         private BluetoothDevice  device;
37         private BluetoothSocket  socket;
38         private InputStream      input;
39         private OutputStream     output;
40         private boolean          pause;
41
42         // Constructor
43         public AltosBluetooth(BluetoothDevice device, Handler handler, boolean pause) {
44                 super(handler);
45                 this.device = device;
46                 this.handler = handler;
47                 this.pause = pause;
48
49                 connect_thread = new ConnectThread();
50                 connect_thread.start();
51         }
52
53         void connected() {
54                 if (closed()) {
55                         AltosDebug.debug("connected after closed");
56                         return;
57                 }
58
59                 AltosDebug.check_ui("connected\n");
60                 try {
61                         synchronized(this) {
62                                 if (socket != null) {
63                                         input = socket.getInputStream();
64                                         output = socket.getOutputStream();
65                                         super.connected();
66                                 }
67                         }
68                 } catch (InterruptedException ie) {
69                         connect_failed();
70                 } catch (IOException io) {
71                         connect_failed();
72                 }
73         }
74
75         private void connect_failed() {
76                 if (closed()) {
77                         AltosDebug.debug("connect_failed after closed");
78                         return;
79                 }
80
81                 close_device();
82                 input = null;
83                 output = null;
84                 handler.obtainMessage(TelemetryService.MSG_CONNECT_FAILED, this).sendToTarget();
85                 AltosDebug.error("ConnectThread: Failed to establish connection");
86         }
87
88         void close_device() {
89                 BluetoothSocket tmp_socket;
90
91                 synchronized(this) {
92                         tmp_socket = socket;
93                         socket = null;
94                 }
95
96                 if (tmp_socket != null) {
97                         try {
98                                 tmp_socket.close();
99                         } catch (IOException e) {
100                                 AltosDebug.error("close_socket failed");
101                         }
102                 }
103         }
104
105         public void close() {
106                 super.close();
107                 input = null;
108                 output = null;
109         }
110
111         private final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
112
113         private void create_socket(BluetoothDevice  device) {
114
115                 BluetoothSocket tmp_socket = null;
116
117                 AltosDebug.check_ui("create_socket\n");
118                 try {
119                         tmp_socket = device.createInsecureRfcommSocketToServiceRecord(SPP_UUID);
120                 } catch (IOException e) {
121                         e.printStackTrace();
122                 }
123                 if (socket != null) {
124                         AltosDebug.debug("Socket already allocated %s", socket.toString());
125                         close_device();
126                 }
127                 synchronized (this) {
128                         socket = tmp_socket;
129                 }
130         }
131
132         private class ConnectThread extends Thread {
133
134                 public void run() {
135                         AltosDebug.debug("ConnectThread: BEGIN (pause %b)", pause);
136                         setName("ConnectThread");
137
138                         if (pause) {
139                                 try {
140                                         Thread.sleep(4000);
141                                 } catch (InterruptedException e) {
142                                 }
143                         }
144
145                         create_socket(device);
146                         // Always cancel discovery because it will slow down a connection
147                         try {
148                                 BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
149                         } catch (Exception e) {
150                                 AltosDebug.debug("cancelDiscovery exception %s", e.toString());
151                         }
152
153                         BluetoothSocket local_socket = null;
154
155                         synchronized (AltosBluetooth.this) {
156                                 if (!closed())
157                                         local_socket = socket;
158                         }
159
160                         if (local_socket != null) {
161                                 try {
162                                         // Make a connection to the BluetoothSocket
163                                         // This is a blocking call and will only return on a
164                                         // successful connection or an exception
165                                         local_socket.connect();
166                                 } catch (Exception e) {
167                                         AltosDebug.debug("Connect exception %s", e.toString());
168                                         try {
169                                                 local_socket.close();
170                                         } catch (Exception ce) {
171                                                 AltosDebug.debug("Close exception %s", ce.toString());
172                                         }
173                                         local_socket = null;
174                                 }
175                         }
176
177                         if (local_socket != null) {
178                                 connected();
179                         } else {
180                                 connect_failed();
181                         }
182
183                         AltosDebug.debug("ConnectThread: completed");
184                 }
185         }
186
187         private synchronized void wait_connected() throws InterruptedException, IOException {
188                 AltosDebug.check_ui("wait_connected\n");
189                 if (input == null && socket != null) {
190                         AltosDebug.debug("wait_connected...");
191                         wait();
192                         AltosDebug.debug("wait_connected done");
193                 }
194                 if (socket == null)
195                         throw new IOException();
196         }
197
198         int write(byte[] buffer, int len) {
199                 if (output == null)
200                         return -1;
201                 try {
202                         output.write(buffer, 0, len);
203                 } catch (IOException ie) {
204                         return -1;
205                 }
206                 return len;
207         }
208
209         int read(byte[] buffer, int len) {
210                 if (input == null)
211                         return -1;
212                 try {
213                         return input.read(buffer, 0, len);
214                 } catch (IOException ie) {
215                         return -1;
216                 }
217         }
218
219         // Stubs of required methods when extending AltosLink
220         public boolean can_cancel_reply()   { return false; }
221         public boolean show_reply_timeout() { return true; }
222         public void hide_reply_timeout()    { }
223
224 }