00001 package com.riverlab.robotmanager.bluetooth;
00002
00003 import java.io.IOException;
00004 import java.io.InputStream;
00005 import java.io.OutputStream;
00006 import java.lang.reflect.InvocationTargetException;
00007 import java.lang.reflect.Method;
00008 import java.nio.ByteBuffer;
00009 import java.text.SimpleDateFormat;
00010 import java.util.ArrayList;
00011 import java.util.Arrays;
00012 import java.util.Calendar;
00013 import java.util.Date;
00014 import java.util.List;
00015 import java.util.concurrent.TimeoutException;
00016
00017 import com.riverlab.robotmanager.MainActivity;
00018 import com.riverlab.robotmanager.RobotManagerApplication;
00019 import com.riverlab.robotmanager.messages.RobotMessage;
00020 import com.riverlab.robotmanager.robot.Robot;
00021 import com.riverlab.robotmanager.voice_recognition.Vocabulary;
00022 import com.riverlab.robotmanager.voice_recognition.VoiceRecognitionThread;
00023
00024 import android.bluetooth.BluetoothAdapter;
00025 import android.bluetooth.BluetoothDevice;
00026 import android.bluetooth.BluetoothSocket;
00027 import android.graphics.Bitmap;
00028 import android.graphics.BitmapFactory;
00029 import android.os.Bundle;
00030 import android.os.Handler;
00031 import android.os.HandlerThread;
00032 import android.os.Looper;
00033 import android.os.Message;
00034 import android.util.Log;
00035
00036 public class ConnectedThread extends HandlerThread
00037 {
00038 private BluetoothAdapter mBluetoothAdapter;
00039 private BluetoothSocket mBtSocket;
00040 private InputStream mInStream;
00041 private OutputStream mOutStream;
00042 private RobotManagerApplication mApplication;
00043 private boolean isShutdown = false;
00044 private Object readWriteLock = new Object();
00045
00046 public static final int CONNECT_MESSAGE = 0;
00047 public static final int DISCONNECT_MESSAGE = 1;
00048 public static final int WRITE_MESSAGE = 2;
00049 public static final int SHUTDOWN_MESSAGE = 3;
00050
00051
00052 private Handler mHandler = null;
00053 private Handler mainHandler;
00054 private Handler voiceHandler;
00055
00056 Thread socketThread;
00057
00058 public ConnectedThread(Handler mainHandler, RobotManagerApplication app)
00059 {
00060 super("Bluetooth Connection Thread");
00061 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
00062 mApplication = app;
00063
00064 socketThread = new Thread()
00065 {
00066 @Override
00067 public void run()
00068 {
00069 receivePackets();
00070 }
00071 };
00072 }
00073
00074 @Override
00075 public void start()
00076 {
00077 super.start();
00078
00079 mHandler = new Handler(getLooper()){
00080 public void handleMessage(Message msg)
00081 {
00082 switch (msg.what)
00083 {
00084 case CONNECT_MESSAGE:
00085 String deviceName = (String)msg.obj;
00086 connect(deviceName);
00087 break;
00088 case DISCONNECT_MESSAGE:
00089 Log.d("ConnectedThread", "Disconnect request received");
00090 disconnect();
00091 break;
00092 case WRITE_MESSAGE:
00093 String msgText = (String)msg.obj;
00094 write(msgText.getBytes());
00095 break;
00096 case SHUTDOWN_MESSAGE:
00097 shutdown();
00098 break;
00099 }
00100 }
00101 };
00102 }
00103
00104 public synchronized boolean isReady()
00105 {
00106 return mHandler != null;
00107 }
00108
00109 public void setHandlers(Handler mainHandler, Handler voiceHandler)
00110 {
00111 this.mainHandler = mainHandler;
00112 this.voiceHandler = voiceHandler;
00113 }
00114
00115 public Handler getHandler()
00116 {
00117 return mHandler;
00118 }
00119
00120 public boolean connect(String deviceName)
00121 {
00122 for (BluetoothDevice device : mBluetoothAdapter.getBondedDevices())
00123 {
00124 if (device.getName().equals(deviceName))
00125 {
00126 Log.d("RobotManagerBluetooth", "Attempting to connect to device");
00127
00128
00129 mBluetoothAdapter.cancelDiscovery();
00130
00131
00132 Log.d("RobotManagerBluetooth", "Attempting to create Rfcomm Socket");
00133 Method m;
00134 try {
00135 m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
00136 mBtSocket = (BluetoothSocket) m.invoke(device, 1);
00137 Log.d("RobotManagerBluetooth", "Rfcomm Socket created");
00138 }
00139 catch (NoSuchMethodException e) {
00140 e.printStackTrace();
00141 return false;
00142 }
00143 catch (IllegalArgumentException e) {
00144 e.printStackTrace();
00145 return false;
00146 } catch (IllegalAccessException e) {
00147 e.printStackTrace();
00148 return false;
00149 } catch (InvocationTargetException e) {
00150 e.printStackTrace();
00151 return false;
00152 }
00153
00154
00155 Log.d("RobotManagerBluetooth", "Attempting to open socket");
00156 try {
00157 mBtSocket.connect();
00158 Log.d("RobotManagerBluetooth", "Connection established");
00159 } catch (IOException e) {
00160 e.printStackTrace();
00161 return false;
00162 }
00163
00164
00165 Log.d("RobotManagerBluetooth", "Sending confirmation message to server");
00166 try {
00167 mOutStream = mBtSocket.getOutputStream();
00168 } catch (IOException e) {
00169 e.printStackTrace();
00170 return false;
00171 }
00172
00173 String message = "Confirm connection\n";
00174 byte[] msgBuffer = message.getBytes();
00175 try {
00176 Log.d("RobotManagerBluetooth", "Writing message");
00177 mOutStream.write(msgBuffer);
00178 Log.d("RobotManagerBluetooth", "Message written");
00179 } catch (IOException e) {
00180 e.printStackTrace();
00181 return false;
00182 }
00183
00184
00185 Log.d("RobotManagerBluetooth", "Listening for confirmation message from server");
00186 try {
00187 mInStream = mBtSocket.getInputStream();
00188 } catch (IOException e) {
00189 e.printStackTrace();
00190 return false;
00191 }
00192
00193 String confirmString = "Connection confirmed\n";
00194 byte[] receivedBytes = new byte[confirmString.getBytes().length];
00195 try
00196 {
00197 mInStream.read(receivedBytes);
00198 } catch (IOException e){
00199 e.printStackTrace();
00200 return false;
00201 }
00202 String receivedString = new String(receivedBytes);
00203 if (receivedString.equals(confirmString))
00204 {
00205 Log.d("RobotManagerBluetooth", "Connection confirmed");
00206 mApplication.setConnectionStatus(true);
00207
00208 Message connectionMessage = mainHandler.obtainMessage(MainActivity.CONNECTION_MESSAGE, "connected");
00209 mainHandler.sendMessageAtFrontOfQueue(connectionMessage);
00210
00211 Message voiceConnectionMessage = voiceHandler.obtainMessage(VoiceRecognitionThread.CONNECTION_MESSAGE,
00212 "connected");
00213 voiceHandler.sendMessage(voiceConnectionMessage);
00214
00215 socketThread.start();
00216
00217 return true;
00218 }
00219 else
00220 {
00221 Log.d("RobotManagerBluetooth", "Confirmation not received");
00222 mApplication.setConnectionStatus(false);
00223 return false;
00224 }
00225 }
00226 }
00227 return false;
00228 }
00229
00230 public synchronized byte[] read()
00231 {
00232 try {
00233 int available = mInStream.available();
00234 if (available > 0)
00235 {
00236 byte[] buffer = new byte[available];
00237 mInStream.read(buffer);
00238 return buffer;
00239 }
00240 else
00241 {
00242 return null;
00243 }
00244 } catch (IOException e) {
00245 e.printStackTrace();
00246 Log.d("ConnectedThread", "Error reading message");
00247 return null;
00248 }
00249 }
00250
00251 public synchronized byte[] read(int length)
00252 {
00253 byte[] buffer = new byte[length];
00254
00255 try {
00256 buffer = new byte[2048];
00257 mInStream.read(buffer, 0, length);
00258 return buffer;
00259 } catch (IOException e) {
00260 e.printStackTrace();
00261 Log.d("ConnectedThread", "Error reading message");
00262 return null;
00263 }
00264 }
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310 private void receivePackets()
00311 {
00312 Log.i("ConnectedThread", "Packet listener thread enabled");
00313
00314 byte[] buffer = new byte[30];
00315 int packetNum = 0;
00316 int packetSize = 0;
00317 String message;
00318
00319 while(mApplication.getConnectionStatus())
00320 {
00321 Log.i("ConnectedThread", "Listening for packet header");
00322
00323 String tempString = "";
00324 while (!hasFullHeader(tempString))
00325 {
00326 byte[] bytes = read(1);
00327 if (bytes != null)
00328 {
00329 String readString = new String(bytes).trim();
00330 tempString += readString;
00331 }
00332 }
00333
00334 String headerString = tempString;
00335 Log.i("ConnectedThread", "Header: " + headerString);
00336
00337 if ((headerString.substring(0, 5).equals("<msg>")) && (headerString.indexOf("</msg>") != -1))
00338 {
00339 headerString = headerString.replace("<msg>", "").replace("</msg>", "");
00340 String[] parts = headerString.split("_DELIM_");
00341 packetNum = Integer.parseInt(parts[0]);
00342 packetSize = Integer.parseInt(parts[1]);
00343 }
00344
00345 Log.i("ConnectedThread", "Expecting " + Integer.toString(packetNum)
00346 + " packets of size " + Integer.toString(packetSize)
00347 + " bytes");
00348
00349 message = getPacketData(packetNum, packetSize);
00350 String[] messageParts = message.split("_DELIM_");
00351 Log.d("ConnectedThread", "Message type: " + messageParts[0]);
00352
00353
00354 if(messageParts[0].equals("robot_configuration"))
00355 {
00356 parseRobotConfiguration(messageParts[1], messageParts[2], messageParts[3]);
00357 }
00358 else if(messageParts[0].equals("text_message"))
00359 {
00360 parseTextMessage(messageParts[1], messageParts[2], messageParts[3]);
00361 }
00362 else if(messageParts[0].equals("image_message"))
00363 {
00364 parseImageMessage(messageParts[1], messageParts[2], messageParts[3], messageParts[4]);
00365 }
00366 }
00367 }
00368
00369 private String getPacketData(int numPackets, int pktSize)
00370 {
00371 Log.i("ConnectedThread", "Getting packet data");
00372
00373 int metaSize = 27;
00374 String pktData = "";
00375 int deltaT = 3000;
00376 double stopTime = System.currentTimeMillis() + deltaT;
00377
00378 for (int i = 0; i < numPackets &&
00379 System.currentTimeMillis() != stopTime; i++)
00380 {
00381 Log.i("ConnectedThread", "Listening for packets");
00382 String tempString = "";
00383 while (!isShutdown)
00384 {
00385 while (!hasFullPacket(tempString))
00386 {
00387 byte[] bytes = read();
00388 if (bytes != null)
00389 {
00390 String readString = new String(bytes).trim();
00391 tempString += readString;
00392 }
00393 }
00394 Log.i("ConnectedThread", "Packet received");
00395 Log.i("ConnectedThread", "Raw: " + tempString);
00396 tempString = conditionData(tempString, i+1);
00397 Log.i("ConnectedThread", "Conditioned: " + tempString);
00398 Log.i("ConnectedThread", "Asking for next packet");
00399 write("_NEXT_\n".getBytes());
00400 break;
00401 }
00402 if (tempString == null)
00403 {
00404 Log.d("ConnectedThread", "Could not read packet #" + Integer.toString(i));
00405 }
00406 else
00407 {
00408 pktData += tempString;
00409 }
00410 }
00411 pktData = pktData.replace("_SPACE_", " ");
00412 return pktData;
00413 }
00414
00415 private boolean hasFullHeader(String strBuffer)
00416 {
00417 int start = strBuffer.indexOf("<msg>");
00418 if (start >= 0)
00419 {
00420 int end = strBuffer.indexOf("</msg>", start);
00421 if (end >= 0)
00422 {
00423 return true;
00424 }
00425 else
00426 {
00427 return false;
00428 }
00429 }
00430 else
00431 {
00432 return false;
00433 }
00434 }
00435
00436
00437 private boolean hasFullPacket(String strBuffer)
00438 {
00439 int start = strBuffer.indexOf("<pkt>");
00440 if (start >= 0)
00441 {
00442 int end = strBuffer.indexOf("</pkt>", start);
00443 if (end >= 0)
00444 {
00445 return true;
00446 }
00447 else
00448 {
00449 return false;
00450 }
00451 }
00452 else
00453 {
00454 return false;
00455 }
00456 }
00457
00458 private String conditionData(String rawString, int expectedIndex)
00459 {
00460 String conditionedString = "";
00461 boolean invalid = false;
00462
00463 if ((rawString.substring(0, 5).equals("<pkt>")) && (rawString.indexOf("</pkt>") != -1))
00464 {
00465 rawString = rawString.replace("<pkt>", "");
00466 Log.d("ConnectedThread", "Remove pkt tags " + rawString);
00467
00468 if ((rawString.substring(0, 7).equals("<index>")) && (rawString.indexOf("</index>") != -1))
00469 {
00470 String pktIndexString = rawString.substring(7, rawString.indexOf("</index>"));
00471 int pktIndex = Integer.parseInt(pktIndexString);
00472
00473 String pktBody = rawString.substring(
00474 rawString.indexOf("</index>") + 8);
00475
00476 if (pktBody.indexOf("</pkt>") != -1)
00477 {
00478 if (expectedIndex == pktIndex)
00479 {
00480 conditionedString = pktBody.substring(0,
00481 pktBody.indexOf("</pkt>"));
00482
00483 conditionedString = conditionedString.replace("_SPACE_", " ");
00484 }
00485 else
00486 {
00487 invalid = true;
00488 Log.i("ConnectedThread", "Packet index does not match expected index");
00489 }
00490 }
00491 else
00492 {
00493 invalid = true;
00494 Log.i("ConnectedThread", "End of packet not read");
00495 }
00496 }
00497 else
00498 {
00499 invalid = true;
00500 Log.i("ConnectedThread", "Index tags not read");
00501 }
00502 }
00503 else
00504 {
00505 invalid = true;
00506 Log.i("ConnectedThread", "Begin packet tag not read");
00507 }
00508
00509 if (invalid)
00510 {
00511 conditionedString = null;
00512 Log.i("ConnectedThread", "Invalid packet");
00513 }
00514
00515 return conditionedString;
00516 }
00517
00518 private void parseRobotConfiguration(String sender, String info, String rawVocab)
00519 {
00520 Log.d("ConnectedThread", "Configuring Robot");
00521 Robot newRobot = new Robot();
00522 newRobot.setName(sender);
00523 newRobot.setInfo(info);
00524 newRobot.setVocabulary(new Vocabulary(rawVocab));
00525
00526 Message msg = voiceHandler.obtainMessage(VoiceRecognitionThread.ADD_VOCAB_MESSAGE, newRobot.getName());
00527 voiceHandler.sendMessageAtFrontOfQueue(msg);
00528
00529 mApplication.addRobot(newRobot);
00530
00531 Log.d("ConnectedThread", "Writing confirmation");
00532 write("configuration complete\n".getBytes());
00533 }
00534
00535
00536 private void parseTextMessage(String sender, String text, String strPriority)
00537 {
00538 Log.d("ConnectedThread", "Reading text message");
00539 RobotMessage msg = new RobotMessage();
00540 msg.setType("Text");
00541 msg.setSender(sender);
00542 msg.setText(text);
00543 msg.setPriority(Integer.parseInt(strPriority));
00544
00545 Calendar cal = Calendar.getInstance();
00546 SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
00547 msg.setTimestamp(sdf.format(cal.getTime()));
00548
00549 Log.d("ConnectedThread", "Adding text message to messages");
00550 mApplication.addMessage(msg);
00551 }
00552
00553 private void parseImageMessage(String sender, String text, String base64Image, String strPriority)
00554 {
00555 Log.d("ConnectedThread", "Reading image message");
00556 RobotMessage msg = new RobotMessage();
00557 msg.setType("Image");
00558 msg.setSender(sender);
00559 msg.setText(text);
00560 msg.setImage(base64Image);
00561 msg.setPriority(Integer.parseInt(strPriority));
00562
00563 Calendar cal = Calendar.getInstance();
00564 SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
00565 msg.setTimestamp(sdf.format(cal.getTime()));
00566
00567 Log.d("ConnectedThread", "Adding text message to messages");
00568 mApplication.addMessage(msg);
00569 }
00570
00571 public void write(byte[] bytes) {
00572 String sentString = new String(bytes);
00573 String confirmString = "Copy: " + sentString;
00574
00575 Log.d("RobotManagerBluetooth", "Acquiring read/write lock");
00576
00577
00578 try {
00579 Log.d("RobotManagerBluetooth", "Writing");
00580 mOutStream.write(bytes);
00581 } catch (IOException e) {
00582
00583
00584 e.printStackTrace();
00585 disconnect();
00586 }
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606 }
00607
00608 private void sendMainMessage(RobotMessage msg)
00609 {
00610 Message mainMsg = new Message();
00611
00612 if (msg.getType().equals("simple"))
00613 {
00614 mainMsg.what = MainActivity.MESSAGE_LIST_MESSAGE;
00615 }
00616
00617 mainMsg.obj = msg;
00618 mHandler.sendMessageAtFrontOfQueue(mainMsg);
00619 }
00620
00621 public void disconnect()
00622 {
00623
00624
00625 write("end connection\n".getBytes());
00626
00627 socketThread.interrupt();
00628 socketThread = null;
00629 mApplication.setConnectionStatus(false);
00630
00631 Message connectionMessage = mainHandler.obtainMessage(MainActivity.CONNECTION_MESSAGE, "disconnected");
00632 mainHandler.sendMessage(connectionMessage);
00633
00634 Message voiceConnectionMessage = voiceHandler.obtainMessage(VoiceRecognitionThread.CONNECTION_MESSAGE, "disconnected");
00635 voiceHandler.sendMessage(voiceConnectionMessage);
00636
00637
00638
00639
00640
00641 }
00642
00643 public void shutdown()
00644 {
00645 if (mApplication.getConnectionStatus())
00646 {
00647 disconnect();
00648 }
00649 isShutdown = true;
00650 mApplication.setConnectedThreadHandler(null);
00651 }
00652 }