2
votes

I have a requirement to implement a solution to read data from an android device, connected to PC via a USB cable. i.e. the phone connected to the PC will receive data through another android device via NFC where the PC - C# program must read the received data from the plugged in android phone as show below.

[PC]<----(2. read data) usb cable----[android phone]<-----NFC (1. transmit string)-----[android phone]

I have implemented data transmission via NFC utlizing the link here - http://developer.android.com/guide/topics/connectivity/nfc/nfc.html . However, I could find any reference as to reading data from the android phone when it receives content (a small string message) via NFC.

I tried many Google searches but ended up empty handed as I am novice in this field. I will really appreciate if you experts could point out some tutorials/ code snippets/ references on how to achieve this task.

Please forgive if this question is repeated or vague. I am a novice to this field and not aware of keywords to look for online help.

Thank you :)

4
It looks to me that this has not much to do with NFC or a third device. You want a program on your PC to read data from an Android device connected to that PC with an USB cable. Or maybe you want the Android device to send data to the PC?greenapps
@greenapps thank you for the reply sir.. yes that is my aim..the C# should poll for NFC messages received to the connected android devices, or the android device connected should send data to the c# program once it receives an NFC message sir.. :) will that be possible? do you have an idea on how to do this?Hasitha Shan
Why has it to be connected with a USB cable?greenapps
@greenapps i thought it would be easier for the C# application retrieve data that way..is there another possible/ easy way?Hasitha Shan
The easiest way is wifi. Just server/client. If you say that C# should retrieve data then where is that data stored/handled on the android?greenapps

4 Answers

5
votes

I think this is what you should do. When the data from NFC is received, store it in the SD Card at a predefined location. At the same time run a continuous thread to do a adb pull for that specific file. If the adb pull downloads the file, you're done.

3
votes

First of all, I'm not a C# programmer, so please forgive me for copy pasting a C# socket client from MSDN examples page.

Basically, if you want to communicate over USB with Android application, you need to instruct your phone to create port forwarding via adb (Android Debug Bridge), and then you can use normal TCP/IP sockets to establish stream communication with your client.

So first, you have to have proper drivers installed on your PC (you can find them on your manufacturers web site), so that when you run adb devices, your phone is correctly identified:

C:\adt-bundle-windows-x86-20140321\sdk\platform-tools>adb devices
List of devices attached
039d78fa2518e606        device

Next thing you need is to setup port forwarding on the Android side, so that socket connections on/to your localhost on your PC will be properly forwarded to the localhost on the phone. This is also done via adb:

C:\adt-bundle-windows-x86-20140321\sdk\platform-tools>adb forward tcp:6000 tcp:6000

Verify that it was successfull:

C:\adt-bundle-windows-x86-20140321\sdk\platform-tools>adb forward --list
039d78fa2518e606 tcp:6000 tcp:6000

And now you can create a regular socket server application on the Android side. I apologize that this example is very simple (I noticed this question very late and didn't have time to implement proper communication protocol). But this should show you how to transfer strings between client and host, and you can implement necessary loops, or more complicated transfer protocols if needed.

Basically this is just the default Android project, with 1 added class, that is run in a separate thread (GUI and network activities cannot be run in same thread).

So, our MainActivity.java looks like this:

package com.example.dataexchange;

import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;

public class MainActivity extends ActionBarActivity {

SocketHandler server;

@Override
protected void onCreate(Bundle savedInstanceState) {

    Log.v("jlumme", "Main/ start network task");

    new Thread(new Runnable() {
        public void run() {
            server = new SocketHandler(6000);
            server.run();
        }
    }).start();

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new PlaceholderFragment())
                .commit();
    }
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {

    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}

/**
 * A placeholder fragment containing a simple view.
 */
public static class PlaceholderFragment extends Fragment {

    public PlaceholderFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_main, container, false);
        return rootView;
    }
}
}

The usual stuff, we just start our SocketHandler class in a separate thread. The SocketThread class looks like this:

package com.example.dataexchange;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

import android.util.Log;

public class SocketHandler implements Runnable {

private Socket socket;
private ServerSocket server;
private PrintWriter out;
private BufferedReader in;

private int socketPort;
SocketHandler(int port) {
    socketPort = port;
}

@Override
public void run() {

    Log.v("jlumme", "Socket thread has started");
    String inputText;

    // TODO Auto-generated method stub
    try {
        Log.v("jlumme", "Starting socket server ");

        server = new ServerSocket(6000);
        socket = server.accept();

        Log.v("jlumme", "Client connected");

        out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())),true); 
        in = new BufferedReader(new InputStreamReader(socket.getInputStream()));                

        while ((inputText = in.readLine()) != null) {
            Log.v("jlumme", "Received:" + inputText);
            out.println("you wrote:" + inputText);
        }

        Log.v("jlumme", "connection established");

    } catch (IOException ioe) {
        ioe.printStackTrace();
    }
}
}

Basically in the run() method you start a new SocketServer, and start waiting for clients. Once a client connects, you setup stream buffers both ways, and start waiting for a message (anything ending with a line break, '\n' will do).

On the C# side, the application is very simple. It connects to localhost port 6000 and sends one line:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class SynchronousSocketClient
{

public static void StartClient() {
    // Data buffer for incoming data.
    byte[] bytes = new byte[1024];

    // Connect to a remote device.
    try {

        IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6000);

        // Create a TCP/IP  socket.
        Socket sender = new Socket(AddressFamily.InterNetwork, 
            SocketType.Stream, ProtocolType.Tcp );

        // Connect the socket to the remote endpoint. Catch any errors.
        try {
            sender.Connect(remoteEP);

            Console.WriteLine("Socket connected to {0}",
                sender.RemoteEndPoint.ToString());

            // Encode the data string into a byte array.
            byte[] msg = Encoding.ASCII.GetBytes("This is a test\n");

            // Send the data through the socket.
            int bytesSent = sender.Send(msg);

            // Receive the response from the remote device.
            int bytesRec = sender.Receive(bytes);
            Console.WriteLine("Echoed test = {0}",
                Encoding.ASCII.GetString(bytes,0,bytesRec));

            // Release the socket.
            sender.Shutdown(SocketShutdown.Both);
            sender.Close();

        } catch (ArgumentNullException ane) {
            Console.WriteLine("ArgumentNullException : {0}",ane.ToString());
        } catch (SocketException se) {
            Console.WriteLine("SocketException : {0}",se.ToString());
        } catch (Exception e) {
            Console.WriteLine("Unexpected exception : {0}", e.ToString());
        }

    } catch (Exception e) {
        Console.WriteLine( e.ToString());
    }
}

public static int Main(String[] args)
{
    StartClient();
    return 0;
}
}

If when execute the C# program, it will send this is a test string to the client, and client will echo it back:

c:\Visual Studio 2013\Projects\ConsoleApplication2\ConsoleApplication2\bin\Debug>ConsoleApplication2.exe
Socket connected to 127.0.0.1:6000
Echoed test = you wrote:This is a test

I wanted to reach the deadline before bounty closes, so currently there is no proper message handling, and c# will exit immediately (while Android side will get confused by this), I apologize for that. But I think once you get this example running, you can easily extend it to your needs, and implement necessary logic to handle terminations and other stuff..

Hope it helps

1
votes

An alternative would be to monitor logcat output: your application can write a message to the logcat output which is monitored via your application.

Sample code from this SO question and other discussions on this other question

But what @Sagar mentioned seems sensible as well and if done right, can prevent any data lost. With the logcat method, if it gets disconnected then any data transferred during the disconnection will get lost.

0
votes

You could just setup an HTTPListener then issue HTTP Requests to the target PC's IP address on a pre-defined port. You'd need to configure the Android app ahead of time to either send the request to a specific IP address or scan a range of IP addresses looking for the correct one (in which case, your listener would need to respond to "searching"-type requests).

Essentially, you're creating a mini-REST service within C#. You can then issue REST API calls from your Android app.