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