|
@@ -0,0 +1,670 @@
|
|
|
+package communication;
|
|
|
+
|
|
|
+import java.io.DataInputStream;
|
|
|
+import java.io.DataOutputStream;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.StreamCorruptedException;
|
|
|
+import java.net.InetSocketAddress;
|
|
|
+import java.net.ServerSocket;
|
|
|
+import java.net.Socket;
|
|
|
+import java.net.SocketException;
|
|
|
+import java.nio.charset.Charset;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.concurrent.BlockingQueue;
|
|
|
+import java.util.concurrent.LinkedBlockingQueue;
|
|
|
+
|
|
|
+import util.Util;
|
|
|
+
|
|
|
+
|
|
|
+ * Basic Usage
|
|
|
+ *
|
|
|
+ * 1. Call {@link #start(int)} or {@link #connect(InetSocketAddress)} to
|
|
|
+ * initiate a connection 2. Wait for {@link #getState()} to return
|
|
|
+ * {@link #STATE_CONNECTED} 3. {@link #write(byte[])} and {@link #read()}
|
|
|
+ * messages. 4. Close the connection with {@link #stop()}. NOTE: This may
|
|
|
+ * invalidate unread data
|
|
|
+ *
|
|
|
+ * Alternatively, you can always call start. And the first side of the
|
|
|
+ * connection to call connect will win.
|
|
|
+ */
|
|
|
+public class Communication {
|
|
|
+
|
|
|
+ public static boolean D = false;
|
|
|
+
|
|
|
+
|
|
|
+ public static final int STATE_NONE = 0;
|
|
|
+ public static final int STATE_LISTEN = 1;
|
|
|
+
|
|
|
+ public static final int STATE_CONNECTING = 2;
|
|
|
+
|
|
|
+ public static final int STATE_CONNECTED = 3;
|
|
|
+
|
|
|
+ public static final int STATE_STOPPED = 4;
|
|
|
+ public static final int STATE_RETRY = 5;
|
|
|
+
|
|
|
+
|
|
|
+ private AcceptThread mSecureAcceptThread;
|
|
|
+ private ConnectThread mConnectThread;
|
|
|
+ private ConnectedThread mConnectedThread;
|
|
|
+
|
|
|
+
|
|
|
+ private static final int MAX_RETRY = 2;
|
|
|
+
|
|
|
+
|
|
|
+ * Private Members
|
|
|
+ **********************/
|
|
|
+
|
|
|
+ private int mNumTries;
|
|
|
+ private int mPort = 0;
|
|
|
+
|
|
|
+ private boolean acceptMode = false;
|
|
|
+
|
|
|
+ protected int mState;
|
|
|
+ protected InetSocketAddress mAddress;
|
|
|
+
|
|
|
+ public Communication() {
|
|
|
+ mState = STATE_NONE;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setTcpNoDelay(boolean on) {
|
|
|
+ if (mConnectedThread != null)
|
|
|
+ mConnectedThread.setTcpNoDelay(on);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * Set the current state of the connection
|
|
|
+ *
|
|
|
+ * @param state
|
|
|
+ * An integer defining the current connection state
|
|
|
+ */
|
|
|
+ protected synchronized void setState(int state) {
|
|
|
+ if (D)
|
|
|
+ Util.debug("setState() " + mState + " -> " + state);
|
|
|
+ mState = state;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * Return the current connection state.
|
|
|
+ */
|
|
|
+ public synchronized int getState() {
|
|
|
+ return mState;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * Start the communication service. Specifically start AcceptThread to begin
|
|
|
+ * a session in listening (server) mode.
|
|
|
+ */
|
|
|
+ public synchronized void start(int port) {
|
|
|
+ if (D)
|
|
|
+ Util.debug("start");
|
|
|
+
|
|
|
+ acceptMode = true;
|
|
|
+
|
|
|
+ startAcceptThread(port);
|
|
|
+
|
|
|
+ mPort = port;
|
|
|
+ mNumTries = 0;
|
|
|
+
|
|
|
+ setState(STATE_LISTEN);
|
|
|
+ }
|
|
|
+
|
|
|
+ private synchronized void startAcceptThread(int port) {
|
|
|
+
|
|
|
+ if (mConnectThread != null) {
|
|
|
+ mConnectThread.cancel();
|
|
|
+ mConnectThread = null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (mConnectedThread != null) {
|
|
|
+ mConnectedThread.cancel();
|
|
|
+ mConnectedThread = null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (mSecureAcceptThread == null) {
|
|
|
+ mSecureAcceptThread = new AcceptThread(port);
|
|
|
+ mSecureAcceptThread.start();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ protected synchronized void retry() {
|
|
|
+ if (D)
|
|
|
+ Util.debug("retry");
|
|
|
+
|
|
|
+ if (D)
|
|
|
+ Util.debug("Retrying in state: " + getState());
|
|
|
+
|
|
|
+ if (mState == STATE_CONNECTED)
|
|
|
+ return;
|
|
|
+
|
|
|
+
|
|
|
+ if (mNumTries >= MAX_RETRY) {
|
|
|
+ signalFailed();
|
|
|
+
|
|
|
+ if (acceptMode)
|
|
|
+ start(mPort);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ startAcceptThread(mPort);
|
|
|
+
|
|
|
+ setState(STATE_RETRY);
|
|
|
+
|
|
|
+ int sleep = (int) (Math.random() * 1000 + 100);
|
|
|
+ if (D)
|
|
|
+ Util.debug("Sleeping: " + sleep);
|
|
|
+ try {
|
|
|
+ Thread.sleep(sleep);
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ Util.debug("Sleep interupted");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (D)
|
|
|
+ Util.debug("Waking up: " + getState());
|
|
|
+
|
|
|
+
|
|
|
+ if (mState != STATE_CONNECTING && mState != STATE_CONNECTED
|
|
|
+ && mConnectedThread == null && mConnectThread == null)
|
|
|
+ connect(mAddress);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * Start the ConnectThread to initiate a connection to a remote device.
|
|
|
+ *
|
|
|
+ * @param address
|
|
|
+ * The address of the server
|
|
|
+ * @param secure
|
|
|
+ * Socket Security type - Secure (true) , Insecure (false)
|
|
|
+ */
|
|
|
+ public synchronized void connect(InetSocketAddress address) {
|
|
|
+ if (D)
|
|
|
+ Util.disp("connect to: " + address);
|
|
|
+
|
|
|
+
|
|
|
+ if (mState == STATE_CONNECTING || mConnectedThread != null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ mNumTries++;
|
|
|
+ mAddress = address;
|
|
|
+
|
|
|
+
|
|
|
+ if (mState == STATE_CONNECTING) {
|
|
|
+ if (mConnectThread != null) {
|
|
|
+ mConnectThread.cancel();
|
|
|
+ mConnectThread = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (mConnectedThread != null) {
|
|
|
+ mConnectedThread.cancel();
|
|
|
+ mConnectedThread = null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ mConnectThread = new ConnectThread(address);
|
|
|
+ mConnectThread.start();
|
|
|
+ setState(STATE_CONNECTING);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * Start the ConnectedThread to begin managing a connection
|
|
|
+ *
|
|
|
+ * @param socket
|
|
|
+ * The Socket on which the connection was made
|
|
|
+ */
|
|
|
+ public synchronized void connected(Socket socket) {
|
|
|
+ if (D)
|
|
|
+ Util.debug("connected");
|
|
|
+
|
|
|
+
|
|
|
+ if (mConnectThread != null) {
|
|
|
+ mConnectThread.cancel();
|
|
|
+ mConnectThread = null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (mConnectedThread != null) {
|
|
|
+ mConnectedThread.cancel();
|
|
|
+ mConnectedThread = null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if (mSecureAcceptThread != null) {
|
|
|
+ mSecureAcceptThread.cancel();
|
|
|
+ mSecureAcceptThread = null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ mConnectedThread = new ConnectedThread(socket);
|
|
|
+ mConnectedThread.start();
|
|
|
+
|
|
|
+ setState(STATE_CONNECTED);
|
|
|
+ }
|
|
|
+
|
|
|
+ protected void connectionFailed() {
|
|
|
+ Util.error("Connection to the device failed");
|
|
|
+
|
|
|
+
|
|
|
+ if (getState() != STATE_STOPPED)
|
|
|
+ retry();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * Indicate that the connection was lost and notify the UI Activity.
|
|
|
+ */
|
|
|
+ protected void connectionLost() {
|
|
|
+ if (D)
|
|
|
+ Util.error("Connection to the device lost");
|
|
|
+
|
|
|
+
|
|
|
+ if (getState() != STATE_STOPPED && acceptMode) {
|
|
|
+ start(mPort);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ protected void signalFailed() {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * Stop all threads
|
|
|
+ */
|
|
|
+ public synchronized void stop() {
|
|
|
+ if (D)
|
|
|
+ Util.debug("stop");
|
|
|
+ setState(STATE_STOPPED);
|
|
|
+
|
|
|
+ if (mConnectedThread != null) {
|
|
|
+ mConnectedThread.cancel();
|
|
|
+ mConnectedThread = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mConnectThread != null) {
|
|
|
+ mConnectThread.cancel();
|
|
|
+ mConnectThread = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mSecureAcceptThread != null) {
|
|
|
+ mSecureAcceptThread.cancel();
|
|
|
+ mSecureAcceptThread = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * Write to the ConnectedThread in an unsynchronized manner
|
|
|
+ *
|
|
|
+ * This does not add message boundries!!
|
|
|
+ *
|
|
|
+ * @param out
|
|
|
+ * The bytes to write
|
|
|
+ * @see ConnectedThread#write(byte[])
|
|
|
+ */
|
|
|
+ public void write(byte[] out) {
|
|
|
+
|
|
|
+ ConnectedThread r;
|
|
|
+
|
|
|
+ synchronized (this) {
|
|
|
+ if (mState != STATE_CONNECTED)
|
|
|
+ return;
|
|
|
+ r = mConnectedThread;
|
|
|
+ }
|
|
|
+
|
|
|
+ r.write(out);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * Write a length encoded byte array.
|
|
|
+ *
|
|
|
+ * @param out
|
|
|
+ */
|
|
|
+ public void writeLengthEncoded(byte[] out) {
|
|
|
+ write("" + out.length);
|
|
|
+ write(out);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static final Charset defaultCharset = Charset.forName("ASCII");
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ public void write(String buffer) {
|
|
|
+ write(buffer, defaultCharset);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * This was added to allow backwords compaitibility with older versions
|
|
|
+ * which used the default charset (usually utf-8) instead of asc-ii. This is
|
|
|
+ * almost never what we want to do
|
|
|
+ */
|
|
|
+ public void write(String buffer, Charset charset) {
|
|
|
+ write(buffer.getBytes(charset));
|
|
|
+ if (D)
|
|
|
+ Util.debug("Write: " + buffer);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * Read a string from Connected Thread
|
|
|
+ *
|
|
|
+ * @see #read()
|
|
|
+ */
|
|
|
+ public String readString() {
|
|
|
+ return new String(read());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * Read from the ConnectedThread in an unsynchronized manner Note, this is a
|
|
|
+ * blocking call
|
|
|
+ *
|
|
|
+ * @return the bytes read
|
|
|
+ * @see ConnectedThread#read()
|
|
|
+ */
|
|
|
+ public byte[] read() {
|
|
|
+
|
|
|
+ ConnectedThread r;
|
|
|
+
|
|
|
+ synchronized (this) {
|
|
|
+ if (mState != STATE_CONNECTED)
|
|
|
+ return null;
|
|
|
+ r = mConnectedThread;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ byte[] readMessage = r.read();
|
|
|
+
|
|
|
+ if (D)
|
|
|
+ Util.debug("Read: " + new String(readMessage));
|
|
|
+ return readMessage;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * Read a specific number of bytes from the ConnectedThread in an
|
|
|
+ * unsynchronized manner Note, this is a blocking call
|
|
|
+ *
|
|
|
+ * @return the bytes read
|
|
|
+ * @see ConnectedThread#read()
|
|
|
+ */
|
|
|
+ public byte[] readLengthEncoded() {
|
|
|
+ int len = Integer.parseInt(readString());
|
|
|
+ ArrayList<byte[]> bytes = new ArrayList<byte[]>();
|
|
|
+ byte[] data = read();
|
|
|
+ if (data.length != len) {
|
|
|
+ bytes.add(data);
|
|
|
+ data = read();
|
|
|
+ }
|
|
|
+
|
|
|
+ byte[] total = new byte[len];
|
|
|
+ int offset = 0;
|
|
|
+ for (byte[] b : bytes) {
|
|
|
+ for (int i = 0; i < b.length; i++) {
|
|
|
+ total[offset++] = b[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return total;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * This thread runs while listening for incoming connections. It behaves
|
|
|
+ * like a server-side client. It runs until a connection is accepted (or
|
|
|
+ * until cancelled).
|
|
|
+ */
|
|
|
+ private class AcceptThread extends Thread {
|
|
|
+
|
|
|
+ private final ServerSocket mmServerSocket;
|
|
|
+
|
|
|
+ public AcceptThread(int port) {
|
|
|
+ ServerSocket tmp = null;
|
|
|
+ try {
|
|
|
+ tmp = new ServerSocket(port);
|
|
|
+ } catch (IOException e) {
|
|
|
+ Util.error("ServerSocket unable to start", e);
|
|
|
+ }
|
|
|
+
|
|
|
+ mmServerSocket = tmp;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void run() {
|
|
|
+ if (D)
|
|
|
+ Util.disp("BEGIN mAcceptThread ");
|
|
|
+ setName("AcceptThread");
|
|
|
+
|
|
|
+ Socket socket = null;
|
|
|
+
|
|
|
+
|
|
|
+ while (mState != STATE_CONNECTED) {
|
|
|
+ try {
|
|
|
+
|
|
|
+
|
|
|
+ socket = mmServerSocket.accept();
|
|
|
+
|
|
|
+ } catch (IOException e) {
|
|
|
+ Util.error("accept() failed", e);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (socket != null) {
|
|
|
+ synchronized (Communication.this) {
|
|
|
+ switch (mState) {
|
|
|
+ case STATE_LISTEN:
|
|
|
+ case STATE_CONNECTING:
|
|
|
+
|
|
|
+ connected(socket);
|
|
|
+ break;
|
|
|
+ case STATE_NONE:
|
|
|
+ case STATE_CONNECTED:
|
|
|
+
|
|
|
+
|
|
|
+ try {
|
|
|
+ socket.close();
|
|
|
+ } catch (IOException e) {
|
|
|
+ Util.error("Could not close unwanted socket", e);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (D)
|
|
|
+ Util.disp("END mAcceptThread");
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public void cancel() {
|
|
|
+ if (D)
|
|
|
+ Util.debug("AcceptThread canceled " + this);
|
|
|
+ try {
|
|
|
+ mmServerSocket.close();
|
|
|
+ } catch (IOException e) {
|
|
|
+ Util.error("close() of server failed", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * This thread runs while attempting to make an outgoing connection with a
|
|
|
+ * device. It runs straight through; the connection either succeeds or
|
|
|
+ * fails.
|
|
|
+ */
|
|
|
+ private class ConnectThread extends Thread {
|
|
|
+ private final Socket mmSocket;
|
|
|
+ private final InetSocketAddress mmAddress;
|
|
|
+
|
|
|
+ public ConnectThread(InetSocketAddress address) {
|
|
|
+ mmAddress = address;
|
|
|
+
|
|
|
+ mmSocket = new Socket();
|
|
|
+
|
|
|
+ try {
|
|
|
+ mmSocket.setTcpNoDelay(true);
|
|
|
+ } catch (SocketException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ */
|
|
|
+ }
|
|
|
+
|
|
|
+ public void run() {
|
|
|
+ Util.debug("BEGIN mConnectThread");
|
|
|
+ setName("ConnectThread");
|
|
|
+
|
|
|
+ try {
|
|
|
+
|
|
|
+
|
|
|
+ mmSocket.connect(mmAddress);
|
|
|
+ } catch (IOException e) {
|
|
|
+
|
|
|
+ try {
|
|
|
+ mmSocket.close();
|
|
|
+ } catch (IOException e2) {
|
|
|
+ Util.error(
|
|
|
+ "unable to close() socket during connection failure",
|
|
|
+ e2);
|
|
|
+ }
|
|
|
+ connectionFailed();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ synchronized (Communication.this) {
|
|
|
+ mConnectThread = null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ connected(mmSocket);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void cancel() {
|
|
|
+ try {
|
|
|
+ mmSocket.close();
|
|
|
+ } catch (IOException e) {
|
|
|
+ Util.error("close() of connect socket failed", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * This thread runs during a connection with a remote device. It handles all
|
|
|
+ * incoming and outgoing transmissions.
|
|
|
+ */
|
|
|
+ private class ConnectedThread extends Thread {
|
|
|
+ private final Socket mmSocket;
|
|
|
+ private final DataInputStream mmInStream;
|
|
|
+ private final DataOutputStream mmOutStream;
|
|
|
+
|
|
|
+ private BlockingQueue<byte[]> mMessageBuffer;
|
|
|
+
|
|
|
+ public ConnectedThread(Socket socket) {
|
|
|
+ Util.debug("create ConnectedThread");
|
|
|
+ mmSocket = socket;
|
|
|
+ DataInputStream tmpIn = null;
|
|
|
+ DataOutputStream tmpOut = null;
|
|
|
+ mMessageBuffer = new LinkedBlockingQueue<byte[]>();
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ try {
|
|
|
+ tmpIn = new DataInputStream(socket.getInputStream());
|
|
|
+ tmpOut = new DataOutputStream(socket.getOutputStream());
|
|
|
+
|
|
|
+ } catch (StreamCorruptedException e) {
|
|
|
+ Util.error("object streams corrupt", e);
|
|
|
+ } catch (IOException e) {
|
|
|
+ Util.error("temp sockets not created", e);
|
|
|
+ }
|
|
|
+
|
|
|
+ mmInStream = tmpIn;
|
|
|
+ mmOutStream = tmpOut;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setTcpNoDelay(boolean on) {
|
|
|
+ if (mmSocket != null)
|
|
|
+ try {
|
|
|
+ mmSocket.setTcpNoDelay(on);
|
|
|
+ } catch (SocketException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * Read from the ConnectedThread in an unsynchronized manner
|
|
|
+ *
|
|
|
+ * This is a blocking call and will only return data if the readLoop
|
|
|
+ * flag is false
|
|
|
+ *
|
|
|
+ * @return the bytes read
|
|
|
+ * @see ConnectedThread#read()
|
|
|
+ */
|
|
|
+ public byte[] read() {
|
|
|
+ try {
|
|
|
+ return mMessageBuffer.take();
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ Util.error("Message Read Interupted");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * Write to the connected OutStream.
|
|
|
+ *
|
|
|
+ * @param buffer
|
|
|
+ * The bytes to write
|
|
|
+ */
|
|
|
+ public void write(byte[] buffer) {
|
|
|
+ try {
|
|
|
+ mmOutStream.writeInt(buffer.length);
|
|
|
+ mmOutStream.write(buffer);
|
|
|
+ mmOutStream.flush();
|
|
|
+ } catch (IOException e) {
|
|
|
+ Util.error("Exception during write", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void run() {
|
|
|
+ Util.disp("BEGIN mConnectedThread");
|
|
|
+
|
|
|
+ int bytes;
|
|
|
+
|
|
|
+
|
|
|
+ while (true) {
|
|
|
+ try {
|
|
|
+
|
|
|
+ bytes = mmInStream.readInt();
|
|
|
+ byte[] buffer = new byte[bytes];
|
|
|
+
|
|
|
+
|
|
|
+ mmInStream.readFully(buffer, 0, bytes);
|
|
|
+
|
|
|
+ try {
|
|
|
+ mMessageBuffer.put(buffer);
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ Util.error("Message add interupted.");
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (IOException e) {
|
|
|
+ if (D)
|
|
|
+ Util.debug("Device disconnected");
|
|
|
+ connectionLost();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void cancel() {
|
|
|
+ try {
|
|
|
+ mmInStream.close();
|
|
|
+ mmOutStream.close();
|
|
|
+ mmSocket.close();
|
|
|
+ } catch (IOException e) {
|
|
|
+ Util.error("close() of connect socket failed", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|