Back a while ago I wrote a post regarding USB cable communication between an Android smartphone and the host machine. I promised some code back then, but forgot to put it. Here is some sample code now.

1a. To enable this to work, the host computer must do what is called port forwarding. The Android debug bridge has this all figured out, you just need to execute the command. What it does, if it executes successfully, is forward all communication targeting localhost on the specified port to the smartphone at the specified port. So, after this, to get a connection, all you have to do is connect to “localhost” on that port you wrote there.

C:\android-sdk-windows\tools\adb.exe forward tcp:38300 tcp:38300

Note: the ports do not have to be the same, I just used the same port for convenience; also you can use any port that will work, the numbers are not special in anyway.

1b. You can also run this directly from your program. Here’s an example of how to do it:

/**
* Runs the android debug bridge command of forwarding the ports
*
*/
private void execAdb() {
// run the adb bridge
try {
Process p=Runtime.getRuntime().exec("C:\\android-sdk-windows\\tools\\adb.exe forward tcp:38300 tcp:38300");
Scanner sc = new Scanner(p.getErrorStream());
if (sc.hasNext()) {
while (sc.hasNext()) System.out.println(sc.next());
Print.fatalError("Cannot start the Android debug bridge");
}
} catch (Exception e) {
Print.fatalError(e.toString());
}
}

2. The server socket needs to be on the smartphone. Not exactly sure why that is, but I couldn’t get this thing to work when it was on the host. My guess is that it has something to do with the way port forwarding works.
Also, it’s usually a good idea to put this part on a separate thread so it doesn’t lock up your UI. The Android tutorial talks more about that in UI design so I won’t.
The sample code that follows does two things. First, it creates a server socket to listen for connections. Second, it actually waits for a connection to be established. It then announces this and goes on to the next class. If in 10 seconds no connection occurs, it times out and stops trying.

NOTE: the following code will not run by itself, because the UI is in an XML file that’s not included, but it should give you a pretty good idea of what the phone code should look like; other than the UI it’s all the code you need.


public class Connection extends Activity implements OnClickListener {

public static final String TAG=”Connection”;
public static final int TIMEOUT=10;
Intent i=null;
TextView tv=null;
private String connectionStatus=null;
private Handler mHandler=null;
ServerSocket server=null;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.connection);

//Set up click listeners for the buttons
View connectButton = findViewById(R.id.connect_button);
connectButton.setOnClickListener(this);

i = new Intent(this, Connected.class);
mHandler=new Handler();
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.connect_button:
tv = (TextView) findViewById(R.id.connection_text);
//initialize server socket in a new separate thread
new Thread(initializeConnection).start();
String msg=”Attempting to connect…”;
Toast.makeText(Connection.this, msg, msg.length()).show();
break;
}
}

private Runnable initializeConnection = new Thread() {
public void run() {

Socket client=null;
// initialize server socket
try{
server = new ServerSocket(38300);
server.setSoTimeout(TIMEOUT*1000);

//attempt to ccept a connection
client = server.accept();
Globals.socketIn=new Scanner(client.getInputStream());
Globals.socketOut = new PrintWriter(client.getOutputStream(), true);
} catch (SocketTimeoutException e) {
// print out TIMEOUT
connectionStatus=”Connection has timed out! Please try again”;
mHandler.post(showConnectionStatus);
} catch (IOException e) {
Log.e(TAG, “”+e);
} finally {
//close the server socket
try {
if (server!=null)
server.close();
} catch (IOException ec) {
Log.e(TAG, “Cannot close server socket”+ec);
}
}

if (client!=null) {
Globals.connected=true;
// print out success
connectionStatus=”Connection was succesful!”;
mHandler.post(showConnectionStatus);

startActivity(i);
}
}
};

/**
* Pops up a “toast” to indicate the connection status
*/
private Runnable showConnectionStatus = new Runnable() {
public void run() {
Toast.makeText(Connection.this, connectionStatus, Toast.LENGTH_SHORT).show();
}
};
}

 

3. The host machine application will then obviously implement a client socket. I use a PrintWriter to write stuff to the output stream and a Scanner to parse what’s coming through the input stream. Obviously there are many other ways to handle this.
Here’s the code I used:


/**
* Initialize connection to the phone
*
*/
public void initializeConnection(){
//Create socket connection
try{
socket = new Socket("localhost", 38300);
out = new PrintWriter(socket.getOutputStream(), true);
//in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
sc=new Scanner(socket.getInputStream());

// add a shutdown hook to close the socket if system crashes or exists unexpectedly
Thread closeSocketOnShutdown = new Thread() {
public void run() {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
};
Runtime.getRuntime().addShutdownHook(closeSocketOnShutdown);
} catch (UnknownHostException e) {
Print.fatalError(“Socket connection problem (Unknown host)”+e.getStackTrace());
} catch (IOException e) {
Print.fatalError(“Could not initialize I/O on socket “+e.getStackTrace());
}
}

4. Putting it all together
So, this is what you have to do (in this order).
- The adb port forwarding command must run on the host computer
- The Android application needs to run, setup a server socket on localhost (on the 2nd port used in the adb command) and then wait to get a connection
- The host computer needs to open up a client socket on localhost (on the 1st port used in the adb command) and connect to the Android phone
- Done! Communicate over sockets as usual.

Hope it’s useful to someone out there! If you have problems trying to get this code working, let me know in the comments and I’ll help you out. When I have time, I will try to actually make two small programs that demonstrate the behavior, but it might be a while before I can do that, life has been very busy lately.