package org.droidklavier.tcp; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import org.droidklavier.BuildConfig; import org.droidklavier.rc.RC; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.InetSocketAddress; import java.net.Socket; public class TCPClient { private static final String TAG = "TCPClient"; private final String HOST; private final int PORT; // Constants that indicate the current connection state public static final int STATE_CONNECTED = 0; public static final int STATE_DISCONNECTED = 1; private final Handler mHandler; private int mState; private Socket mSocket; private PrintWriter mWriter; private BufferedReader mReader; private ConnectedThread mConnectedThread; private KeepAliveThread mKeepAliveThread; public TCPClient(String host, int port, Handler handler) { HOST = host; PORT = port; mState = STATE_DISCONNECTED; mHandler = handler; } public synchronized boolean isConnected() { return mState == STATE_CONNECTED; } private synchronized void setState(int state) { if (BuildConfig.DEBUG) { Log.d(TAG, "setState() " + mState + " -> " + state); } mState = state; // Give the new state to the Handler so the UI Activity can update mHandler.obtainMessage(TCPHandler.MESSAGE_STATE_CHANGE, state, -1).sendToTarget(); } public synchronized void sendMessage(String message) { ConnectedThread r; // Synchronize a copy of the ConnectedThread synchronized (this) { if (mState != STATE_CONNECTED) { return; } r = mConnectedThread; } // Perform the write unsynchronized r.write(message); } public synchronized void connect() { try { Log.e(TAG, "Connecting..."); mSocket = new Socket(); mSocket.connect(new InetSocketAddress(HOST, PORT), 10000); // send the message to the server mWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream())), true); // receive the message which the server sends back mReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream())); setState(STATE_CONNECTED); } catch (IOException e) { connectionFailed(); Log.e(TAG, "Connection Error", e); } } public synchronized void stop() { setState(STATE_DISCONNECTED); if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread.interrupt(); mConnectedThread = null; } if (mKeepAliveThread != null) { mKeepAliveThread.interrupt(); mKeepAliveThread = null; } } public synchronized void connected() { if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } mConnectedThread = new ConnectedThread(); mConnectedThread.start(); mKeepAliveThread = new KeepAliveThread(); mKeepAliveThread.start(); // Send the address of connected device back to the UI Activity Message msg = mHandler.obtainMessage(TCPHandler.MESSAGE_CONNECTED_ADDRESS); Bundle bundle = new Bundle(); bundle.putString(TCPHandler.CONNECTED_ADDRESS, HOST); msg.setData(bundle); mHandler.sendMessage(msg); } private void connectionLost() { if (BuildConfig.DEBUG) { Log.e(TAG, "Connection lost"); } stop(); mHandler.obtainMessage(TCPHandler.MESSAGE_CONNECTION_LOST).sendToTarget(); } private void connectionFailed() { if (BuildConfig.DEBUG) { Log.e(TAG, "Connection failed"); } stop(); mHandler.obtainMessage(TCPHandler.MESSAGE_CONNECTION_FAILED).sendToTarget(); } private class ConnectedThread extends Thread { public ConnectedThread() { setName("ConnectedThread"); } @Override public void run() { String message; try { while (isConnected()) { message = mReader.readLine(); if (message != null) { // Send the obtained bytes to the UI Activity mHandler.obtainMessage(TCPHandler.MESSAGE_READ, message.length(), -1, message).sendToTarget(); } message = null; } } catch (Exception e) { connectionLost(); } finally { cancel(); } } public void write(String message) { if (mWriter != null && !mWriter.checkError()) { mWriter.println(message); mWriter.flush(); // Share the sent message back to the UI Activity mHandler.obtainMessage(TCPHandler.MESSAGE_WRITE, -1, -1, message).sendToTarget(); } } public void cancel() { try { mSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } private class KeepAliveThread extends Thread { public KeepAliveThread() { setName("KeepAliveThread"); } @Override public void run() { try { // Send <active /> message every 3 seconds while (isConnected()) { sleep(3000); sendMessage(RC.active()); } } catch (InterruptedException e) { // e.printStackTrace(); } } } }