UDP server running on android for LAN - java

i have server and clients running in the LAN,but my server don't accept more than one message from client app. in LAN, what code shall i put in while loop in order to accept as many messages as i send from client app ?
My server class is:
public class MainActivity extends Activity {
private Boolean shouldRestartSocketListen=true;
TextView tv1;
//MulticastLock lock;
static String UDP_BROADCAST = "UDPBroadcast";
DatagramSocket socket;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv1=(TextView)findViewById(R.id.textView1);
startListenForUDPBroadcast();
// lock.release();
}
private void listenAndWaitAndThrowIntent(InetAddress broadcastIP, Integer port) throws Exception {
byte[] recvBuf = new byte[15000];
if (socket == null || socket.isClosed()) {
socket = new DatagramSocket(port, broadcastIP);
//socket.setBroadcast(true);
}
//socket.setSoTimeout(1000);
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
Log.e("UDP", "Waiting for UDP broadcast");
socket.receive(packet);
String senderIP = packet.getAddress().getHostAddress();
String message = new String(packet.getData()).trim();
// Log.e("UDP", "Got UDB broadcast from " + senderIP + ", message: " + message);
tv1.setText(message);
// broadcastIntent(senderIP, message);
socket.close();
}
private void broadcastIntent(String senderIP, String message) {
Intent intent = new Intent(MainActivity.UDP_BROADCAST);
intent.putExtra("sender", senderIP);
intent.putExtra("message", message);
sendBroadcast(intent);
}
Thread UDPBroadcastThread;
void startListenForUDPBroadcast() {
UDPBroadcastThread = new Thread(new Runnable() {
public void run() {
try {
InetAddress broadcastIP = InetAddress.getByName("192.168.1.255"); //172.16.238.42 //192.168.1.255
Integer port = 11111;
while (shouldRestartSocketListen) {
listenAndWaitAndThrowIntent(broadcastIP, port);
}
//if (!shouldListenForUDPBroadcast) throw new ThreadDeath();
} catch (Exception e) {
Log.i("UDP", "no longer listening for UDP broadcasts cause of error " + e.getMessage());
}
}
});
UDPBroadcastThread.start();
}
void stopListen() {
shouldRestartSocketListen = false;
socket.close();
}
public void onCreate() {
};
#Override
public void onDestroy() {
stopListen();
}
public IBinder onBind(Intent intent) {
return null;
}
}

Don't close the socket unless you want to stop listening (put it outside your while loop).
I've tried using UDPFlood v2.0 from McAfee, with the socket.close() like you have it, you will miss messages as soon there are more than ~5 packets per second (depending how fast your other tasks are). The messages get buffered in your socket (OS) but you discard them by closing it.

Related

How to connect to PC (server) using sockets with Android app (client)?

I have a server set up on my PC (using Hercules), which is listening on a port # and waiting for a connection. I can't get the android app to receive messages from the server however on my android emulator (Strangely I can send messages to the server), and I can't do either from my physical android phone.
All the examples I'm finding online involve android devices connecting to each other, like this one: https://www.coderzheaven.com/2017/05/01/client-server-programming-in-android-send-message-to-the-client-and-back/
Would I still be able to connect to a PC by just implementing the client side on my android app? What changes would I have to make otherwise?
Directly copy pasting hasn't worked for me...
(Btw the phone and PC are both connected to the same ethernet network, not wifi if that makes a difference)
Thanks!
edit: Turns out my PC was on a different subnet from my phyiscal android phone, and so changing the PC to be on the same subnet as the phone fixed the problem of my phone not being able to even connect, but now it can connect it seems and send messages to the PC, but again not able to receive messages from the hercules server
edit2: My client code (android app)
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
public static final int SERVERPORT = xxxx;
public static final String SERVER_IP = "xxx.xxx.x.xxx";
private ClientThread clientThread;
private Thread thread;
private LinearLayout msgList;
private Handler handler;
private int clientTextColor;
private EditText edMessage;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("Client");
clientTextColor = ContextCompat.getColor(this, R.color.colorAccent);
handler = new Handler();
msgList = findViewById(R.id.msgList);
edMessage = findViewById(R.id.edMessage);
}
public TextView textView(String message, int color) {
if (null == message || message.trim().isEmpty()) {
message = "<Empty Message>";
}
TextView tv = new TextView(this);
tv.setTextColor(color);
tv.setText(message + " [" + getTime() + "]");
tv.setTextSize(20);
tv.setPadding(0, 5, 0, 0);
return tv;
}
public void showMessage(final String message, final int color) {
handler.post(new Runnable() {
#Override
public void run() {
msgList.addView(textView(message, color));
}
});
}
#Override
public void onClick(View view) {
if (view.getId() == R.id.connect_server) {
msgList.removeAllViews();
showMessage("Connecting to Server...", clientTextColor);
clientThread = new ClientThread();
thread = new Thread(clientThread);
thread.start();
showMessage("Connected to Server...", clientTextColor);
return;
}
if (view.getId() == R.id.send_data) {
String clientMessage = edMessage.getText().toString().trim();
showMessage(clientMessage, Color.BLUE);
if (null != clientThread) {
clientThread.sendMessage(clientMessage);
}
}
}
class ClientThread implements Runnable {
private Socket socket;
private BufferedReader input;
#Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVERPORT);
this.input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (true) {
String message = input.readLine();
if (null == message || "Disconnect".contentEquals(message)) {
Thread.interrupted();
message = "Server Disconnected.";
showMessage(message, Color.RED);
break;
}
showMessage("Server: " + message, clientTextColor);
}
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
void sendMessage(final String message) {
new Thread(new Runnable() {
#Override
public void run() {
try {
if (null != socket) {
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),
true);
out.println(message);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
String getTime() {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
return sdf.format(new Date());
}
#Override
protected void onDestroy() {
super.onDestroy();
if (null != clientThread) {
clientThread.sendMessage("Disconnect");
clientThread = null;
}
}
}

TCP Client: receive bytes from TCP Connection - Java, Android

I am developing an Android App which receives some data from a server.
I used this tutorial for the TCP Client: TCP Tutorial
Unlike in the tutorial, I need the data as byte[] and not as a String but I can't figure out how to do this.
My TCP Client:
public class TCPClient {
private OnMessageReceived mMessageListener = null;
private BufferedInputStream input;
private byte[] serverMessage; // message received from server
private boolean mRun = false;
/**
* Constructor:
* OnMessagedReceived listens for the messages received from server.
*/
public TCPClient(OnMessageReceived listener) {
mMessageListener = listener;
}
/**
* Connection thread
*/
public void run() {
mRun = true;
try {
// Server address:
InetAddress serverAddr = InetAddress.getByName(10.0.0.170);
Log.e("TCP Client", "C: Connecting...");
// Connection socket:
Socket socket = new Socket(serverAddr, 4848);
try {
// Input stream from server:
input = new BufferedInputStream(socket.getInputStream());
// Listen for messages from server:
while (mRun) {
int bytesRead = input.read();
serverMessage = new byte[bytesRead];
if (serverMessage != null && mMessageListener != null) {
mMessageListener.messageReceived(serverMessage);
}
serverMessage = null; // reset serverMessage
}
} catch (Exception e) {
Log.e("TCP", "S: Error", e);
} finally {
socket.close();
}
} catch (Exception e) {
Log.e("TCP", "C: Error", e);
}
}
public void stopClient(){
mRun = false;
}
/**
* The method messageReceived(byte[] message) must be implemented in the
* MainActivity class at on asynckTask doInBackground
*/
public interface OnMessageReceived {
public void messageReceived(byte[] message);
}
}
Main Activity:
public class MainActivity extends AppCompatActivity {
// TCP Connection:
private TCPClient mTcpClient;
connectTask mConnectTask;
Button connectBtn;
// Debugging variable:
private static final String TAG = MainActivity.class.getName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Relate Button and EditText from java to the one in XML:
connectBtn = (Button) findViewById(R.id.connectBtn);
mConnectTask = new connectTask(); // prepare for TCP connection
// Connect to Server after connect btn pressed
connectBtn.setOnClickListener(
new View.OnClickListener() {
public void onClick(View view) {
Log.i(TAG, "Connect button pressed.");
mConnectTask.execute(); // starts Async task
}
}
);
}
public class connectTask extends AsyncTask<byte[], byte[], TCPClient> {
#Override
protected TCPClient doInBackground(byte[]... message) {
// Create a TCPClient object
mTcpClient = new TCPClient(new TCPClient.OnMessageReceived() {
#Override
// Implementation of messageReceived method
public void messageReceived(byte[] message) {
publishProgress(message); // calls the onProgressUpdate method
}
});
mTcpClient.run();
return null;
}
#Override
protected void onProgressUpdate(byte[]... values) {
super.onProgressUpdate(values);
byte b[] = values[0];
// TODO delete
String str = new String(b, Charset.forName("UTF-8"));
Log.d(TAG, "Data received: " + str);
for (int i = 0; i < b.length; i++) {
int c = b[i] & 0xFF;
Log.d(TAG, "c: " + c);
// Further processing where data is needed as byte[]
}
}
}
}
The Log.d
Log.d(TAG, "Data received: " + str);
logs out that data (unrecognizable bytes) is received. But when I log out c, which is supposed to be the received byte as an int, it is always 0.
Any help is highly appreciated :)

Why are my client threads/listeners not receiving broadcasted messages from the server?

I made a simple prototype of a client-server application on Android
I managed to connect two clients to the server and the server can receive their messages. The problem now is that I can't seem to broadcast/receive the messages to other clients.
I try to broadcast the received message through a for loop in the Server class:
private void broadcastMessage(String message) {
for (int i = 0, j = clients.size(); i <= j; i++) {
PrintWriter out = null;
Socket socket = clients.get(i);
try {
out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())), true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// WHERE YOU ISSUE THE COMMANDS
out.println(message);
Log.d("SERVER Loop", "Broadcasting messages...");
out.close();
}
Log.d("SERVER", "Message Brodcasted");
}
This I then try to receive through a listener in the Client class :
public class ClientThreadListener implements Runnable {
protected Socket serverSocket = null;
protected String mMsgFromServer;
public ClientThreadListener(Socket serverSocket) {
this.serverSocket = serverSocket;
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
serverSocket.getInputStream()));
while ((mMsgFromServer = in.readLine()) != null) {
Log.d("MESSAGE FROM SERVER: ", mMsgFromServer);
handler.post(new Runnable() {
#Override
public void run() {
msgFromOtherClients.append('\n'
+ "Message From Server: " + mMsgFromServer);
}
});
}
} catch (Exception e) {
Log.e("ClientListener", "C: Error", e);
connected = false;
}
}
}
I don't get any errors or force closes though. Forgive me I know it is very messy but please bear with me and please focus on the issue at hand instead :D
Here is the full code for the Server class
public class Server extends Activity {
private TextView serverStatus;
// DEFAULT IP
public static String SERVERIP = "10.0.2.15";
// DESIGNATE A PORT
public static final int SERVERPORT = 8080;
private Handler handler = new Handler();
private ServerSocket serverSocket;
private String mMsgFromClient;
private MultiThreadedServer server;
private ArrayList<Socket> clients = new ArrayList<Socket>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.server);
serverStatus = (TextView) findViewById(R.id.server_status);
// SERVERIP = getLocalIpAddress();
server = new MultiThreadedServer(8080);
new Thread(server).start();
}
public class MultiThreadedServer implements Runnable {
protected int serverPort = 8080;
protected ServerSocket serverSocket = null;
protected boolean isStopped = false;
protected Thread runningThread = null;
public MultiThreadedServer(int port) {
this.serverPort = port;
}
public void run() {
synchronized (this) {
this.runningThread = Thread.currentThread();
}
openServerSocket();
while (!isStopped()) {
Socket clientSocket = null;
try {
clientSocket = this.serverSocket.accept();
clients.add(clientSocket);
} catch (IOException e) {
if (isStopped()) {
Log.d("SERVER TEXT", "Server Stopped.");
return;
}
throw new RuntimeException(
"Error accepting client connection", e);
}
new Thread(new WorkerRunnable(clientSocket, this)).start();
}
Log.d("SERVER TEXT", "Server Stopped.");
}
private synchronized boolean isStopped() {
return this.isStopped;
}
public synchronized void stop() {
this.isStopped = true;
try {
this.serverSocket.close();
} catch (IOException e) {
throw new RuntimeException("Error closing server", e);
}
}
private void openServerSocket() {
try {
this.serverSocket = new ServerSocket(this.serverPort);
} catch (IOException e) {
throw new RuntimeException("Cannot open port 8080", e);
}
}
private void broadcastMessage(String message) {
for (int i = 0, j = clients.size(); i <= j; i++) {
PrintWriter out = null;
Socket socket = clients.get(i);
try {
out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())), true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// WHERE YOU ISSUE THE COMMANDS
out.println(message);
Log.d("SERVER Loop", "Broadcasting messages...");
out.close();
}
Log.d("SERVER", "Message Brodcasted");
}
}
public class WorkerRunnable implements Runnable {
protected Socket clientSocket = null;
protected String mMsgFromClient = null;
private UUID id;
public WorkerRunnable(Socket clientSocket, MultiThreadedServer server) {
this.clientSocket = clientSocket;
id = UUID.randomUUID();
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
while ((mMsgFromClient = in.readLine()) != null) {
handler.post(new Runnable() {
#Override
public void run() {
serverStatus.append('\n'
+ "Message From Client ID " + getID()
+ ": " + mMsgFromClient);
}
});
}
Log.d("SERVERTEXT", "Proceed to broadcast");
server.broadcastMessage(mMsgFromClient);
} catch (IOException e) {
Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
serverStatus
.append('\n'
+ "Message From Client ID "
+ getID()
+ ": "
+ "Oops. Connection interrupted. Please reconnect your phones.");
}
});
e.printStackTrace();
}
}
private String getID() {
return id.toString();
}
}
}
Here is the full code for the Client class
public class Client extends Activity {
private EditText serverIp;
private EditText chatMsg;
private Button connectPhones;
private Button sendMsg;
private TextView msgFromOtherClients;
private String serverIpAddress = "";
private boolean connected = false;
private boolean willSendMsg = false;
private Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.client);
serverIp = (EditText) findViewById(R.id.server_ip);
connectPhones = (Button) findViewById(R.id.connect_phones);
connectPhones.setOnClickListener(connectListener);
chatMsg = (EditText) findViewById(R.id.chat_msg);
sendMsg = (Button) findViewById(R.id.send_msg);
sendMsg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
willSendMsg = true;
}
});
msgFromOtherClients = (TextView) findViewById(R.id.msg_from_other_clients);
}
private OnClickListener connectListener = new OnClickListener() {
#Override
public void onClick(View v) {
if (!connected) {
serverIpAddress = serverIp.getText().toString();
if (!serverIpAddress.equals("")) {
Thread cThread = new Thread(new ClientThread());
cThread.start();
}
}
}
};
public class ClientThread implements Runnable {
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(serverIpAddress);
Log.d("ClientActivity", "C: Connecting...");
Socket socket = new Socket(serverAddr, Server.SERVERPORT);
connected = true;
Thread listener = new Thread(new ClientThreadListener(new Socket(serverAddr, Server.SERVERPORT)));
listener.start();
while (connected) {
if (willSendMsg) {
willSendMsg = false;
try {
Log.d("ClientActivity", "C: Sending command.");
PrintWriter out = new PrintWriter(
new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream())), true);
// WHERE YOU ISSUE THE COMMANDS
out.println(chatMsg.getText().toString());
Log.d("ClientActivity", "C: Sent.");
} catch (Exception e) {
Log.e("ClientActivity", "S: Error", e);
}
}
}
socket.close();
Log.d("ClientActivity", "C: Closed.");
} catch (Exception e) {
Log.e("ClientActivity", "C: Error", e);
connected = false;
}
}
}
public class ClientThreadListener implements Runnable {
protected Socket serverSocket = null;
protected String mMsgFromServer;
public ClientThreadListener(Socket serverSocket) {
this.serverSocket = serverSocket;
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
serverSocket.getInputStream()));
while ((mMsgFromServer = in.readLine()) != null) {
Log.d("MESSAGE FROM SERVER: ", mMsgFromServer);
handler.post(new Runnable() {
#Override
public void run() {
msgFromOtherClients.append('\n'
+ "Message From Server: " + mMsgFromServer);
}
});
}
} catch (Exception e) {
Log.e("ClientListener", "C: Error", e);
connected = false;
}
}
}
}
Your code has some issue that prevents it from working.
As already said in other answers, in your code you are closing the socket output stream right after sending the message to the client. call close() only out of your for message loop. Of course closing the socket in the client will have the same effect as closing it on the server. You must close the sockets only when client and server have finished talking. Closing it while transmitting data it's like hanging up the phone in the middle of a conversation.
Second, you create a new socket on the client side:
Log.d("ClientActivity", "C: Connecting...");
Socket socket = new Socket(serverAddr, Server.SERVERPORT);
but then you pass to the listener another, newly created, socket (I suppose this is not intended):
connected = true;
Thread listener = new Thread(new ClientThreadListener(new Socket(serverAddr, Server.SERVERPORT)));
listener.start();
Third, always call flush() on an output stream right after sending data, or the data will likely not be sent (the send methods will just enqueue your data in the sending buffer).
Last (This may not be useful to you since I don't know your ultimate goal), if you need to send and receive on sockets, 90% of the time it's better and easier to do this asinchronously, using separate threads for listening and sending.
If it still doesn't work, add here some output or log trace from logcat.
You need to move the line:
server.broadcastMessage(mMsgFromClient);
inside the while:
while ((mMsgFromClient = in.readLine()) != null) {
handler.post(new Runnable() {
#Override
public void run() {
serverStatus.append('\n'
+ "Message From Client ID " + getID()
+ ": " + mMsgFromClient);
}
});
// HERE
Log.d("SERVERTEXT", "Proceed to broadcast");
server.broadcastMessage(mMsgFromClient);
}
Otherwise, you'll only broadcast null.
EDIT: You should make sure that mMsgFromClient is not changed between posting the new Runnable and it actually executing. The best way is to initialize a field in the anonymous class with the current value, and log the value of that field instead.
EDIT2: Unless your server is supposed to close its connection to a client after sending it a broadcast message, you should use out.flush() instead of out.close() in the broadcastMessage method. It's preferrable that client connections are closed after a timeout, or just let the clients disconnect, again with a timeout.
Otherwise, your test will be very limited most of the times: a client connects and sends a message; then it receives its own message and the server closes the connection.
Please try to use AsyncTask in android which will create separate thread for communication with server.

Socket can be send only once and the Textview is not gathering the information from the server

I had two issues in the program I am making... the thing is that I want to send by a Edittext that information to a server via UDP....the thing is that the program only works the first time I run the program, I mean, if i open the application and write some text, the information is sended to the server, but if I type another thing and press to button so the new information is sended it doesn't work... the other thing is that the TextView is not appending the information, and the server send some info but the application is not gathering that information... so if someone had a clue why is this happening or what I am doing wrong I appreciated any help!... Thanks in advice...
here is the code:
public class MainActivity extends Activity implements View.OnClickListener {
public static final String SERVERIP = "190.99.20.200";
public static final int SERVERPORT = 5153;
public TextView serverResponse;
public EditText messageToSend;
public Button btnSend;
public boolean start;
public Handler handler;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
serverResponse = (TextView)findViewById(R.id.textView);
messageToSend = (EditText)findViewById(R.id.editText);
btnSend = (Button)findViewById(R.id.button);
btnSend.setOnClickListener(this);
start = false;
new Thread(new Server()).start();
try{
Thread.sleep(500);
}catch (InterruptedException e){
updatetrack("Error on Server:" + e.getMessage());
}
new Thread(new Client()).start();
handler = new Handler(){
public void handledMessage(Message msg){
String text = (String)msg.obj;
serverResponse.append(text);
}
};
}
public class Client implements Runnable {
#Override
public void run() {
while(start == false)
{
}
try{
Thread.sleep(500);
}catch (InterruptedException e1){
e1.printStackTrace();
}
try{
InetAddress serverAddres = InetAddress.getByName(SERVERIP);
updatetrack("Client:Start connectingn");
DatagramSocket socket = new DatagramSocket();
byte[] buffer;
if(!messageToSend.getText().toString().isEmpty())
{
buffer = messageToSend.getText().toString().getBytes();
}
else
{
buffer = ("Message from android").getBytes();
}
DatagramPacket packet = new DatagramPacket(buffer, buffer.length,serverAddres,SERVERPORT);
updatetrack("Client:Sending" + new String(buffer)+ "'n");
socket.send(packet);
updatetrack("Client: Messange sentn");
updatetrack("Client: Succed!n ");
socket.close();
}catch (Exception e){
updatetrack("Client:Error!n" + e.getMessage());
}
}
}
public class Server implements Runnable{
#Override
public void run() {
while (start == false)
{
}
try{
InetAddress serverAddress = InetAddress.getByName(SERVERIP);
updatetrack("nServer: Start connectingn");
DatagramSocket socket = new DatagramSocket(SERVERPORT, serverAddress);
byte[] buffer = new byte[17];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
updatetrack("Server: Receivingn");
socket.receive(packet);
updatetrack("Server: Message received:" + new String(packet.getData())+"'n");
updatetrack("Server : Succed!n");
}catch (Exception e){
updatetrack("Server: Error!n"+ e.getMessage());
}
}
}
public void onClick(View view)
{
start = true;
}
public void updatetrack(String s)
{
Message msg = new Message();
String textTochange = s;
msg.obj = textTochange;
handler.sendMessage(msg);
}
}
The run method in your server class will run only once.
while(start == false){
}
This while loop will continue to loop until you call the onClick method, at which point the rest of the code in the run() method is executed, and the server thread killed. You need to rearrange your code a little, and place it inside the while loop:
public void run() {
while (true){
try{
InetAddress serverAddress = InetAddress.getByName(SERVERIP);
updatetrack("nServer: Start connectingn");
DatagramSocket socket = new DatagramSocket(SERVERPORT, serverAddress);
byte[] buffer = new byte[17];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
updatetrack("Server: Receivingn");
socket.receive(packet);
updatetrack("Server: Message received:" + new String(packet.getData())+"'n");
updatetrack("Server : Succed!n");
}catch (Exception e){
updatetrack("Server: Error!n"+ e.getMessage());
}
}
}

Prompted for Bluetooth PIN when connecting to already paired device on Android

I am developing an Android app to connect to a simple device that supports the bluetooth serial port profile (SPP). I am able to successfully connect and exchange data, but each time I connect the user is prompted to enter the PIN for the device.
In the bluetooth settings I can see that the device is 'paired by not connected'.
The prompt is an issue because if the user is not quick enough in entering the PIN, the socket connect times out and the user must try again.
Relevant bits of code below...
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.scanlayout);
...
_Context = this;
_ActivityCreated = true;
_ReceivedText = (TextView)findViewById(R.id._Scan_Results);
_BluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
_BluetoothDevice = _BluetoothAdapter.getRemoteDevice(_DeviceAddress);
_BusySpinner = ProgressDialog.show(_Context, "", "Connecting to scanner...");
new ConnectToScannerTask().execute(_BluetoothDevice);
}
private final Handler scanReceivedHandler = new Handler()
{
#Override
public void handleMessage(Message message)
{
String receivedText = (String)message.obj;
_ReceivedText.setText(receivedText);
}
};
private class ConnectToScannerTask extends AsyncTask<BluetoothDevice, Void, InputStream>
{
#Override
protected InputStream doInBackground(BluetoothDevice... params)
{
BluetoothDevice device = params[0];
try
{
_Socket = device.createRfcommSocketToServiceRecord(WELL_KNOWN_UUID);
_BluetoothAdapter.cancelDiscovery();
_Socket.connect();
return _Socket.getInputStream();
}
catch (IOException e)
{
Log.d("ScanActivity.ConnectToScannerTask.doInBackground", e.getMessage());
}
return null;
}
#Override
protected void onPostExecute(final InputStream result)
{
_BusySpinner.dismiss();
if (result == null)
{
_ReceivedText.setText("Failed to connect to scanner.");
return;
}
Thread thread = new Thread()
{
#Override
public void run()
{
byte[] buffer = new byte[1024];
try
{
while (_ActivityCreated)
{
Arrays.fill(buffer, (byte) 0);
int bytesRead = result.read(buffer);
if (bytesRead > 0)
{
Message message = scanReceivedHandler.obtainMessage(1, new String(buffer));
message.sendToTarget();
Log.e("ScanActivity", "Received: " + new String(buffer));
}
if (bytesRead < 0)
{
break;
}
}
Message message = scanReceivedHandler.obtainMessage(1, "End of Stream");
message.sendToTarget();
Log.e("ScanActivity", "End of Stream");
}
catch (Exception e)
{
Message message = scanReceivedHandler.obtainMessage(1, "Connection to scanner lost");
message.sendToTarget();
Log.e("ScanActivity", e.getMessage());
}
try
{
_Socket.close();
}
catch (IOException e)
{
Log.e("ScanActivity", e.getMessage());
}
}
};
thread.start();
}
}
As long as the user is quick about entering the PIN, the connect succeeds and I can receive data. My hunch is that I am missing a setup step. I'm not that familiar with the specifics of BT, though, so I am not sure if this might be an issue where the device is forcing the PIN to be entered?
This might be a problem with the remote device that does not keep the device bonded, (meaning storing the link key to be used in subsequent connect) that will result in re-pairing each time and requiring the PIN to be entered.
Android should typically store the bonding information once it has paired successfully.

Categories

Resources