I am developing a server in VB.Net (Visual Studio) and a client in Java (Android Studio). My server sets a UUID with the following code: Dim serviceGuid As New Guid("00001101-0000-1000-8000-00805F9B34FB")
. How can I enable the client to automatically discover which device the server is running on so that it can establish the connection with the correct device? My android client code scan all devices and show all devices into ListView. However, I would like the client to be able to identify which device in the list is hosting the server.I have tried several methods, but without success. Can anyone help me?
This is the server code:
Imports InTheHand.Net.Bluetooth
Imports InTheHand.Net.Sockets
Imports System.IO
Imports System.Text
Imports System.Threading
Public Class Form1
Private btListener As BluetoothListener
Private btClient As BluetoothClient
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
StartBTServer()
End Sub
Private Sub StartBTServer()
Try
Dim serviceGuid As New Guid("00001101-0000-1000-8000-00805F9B31FF")
btListener = New BluetoothListener(serviceGuid)
btListener.Start()
Console.WriteLine("Server started...")
Task.Run(Sub()
While True
Try
Console.WriteLine("Await connections...")
btClient = btListener.AcceptBluetoothClient()
Dim writer As New StreamWriter(btClient.GetStream(), Encoding.UTF8) With {
.AutoFlush = True
}
Dim localRadio As BluetoothRadio = BluetoothRadio.Default
If localRadio IsNot Nothing Then
writer.WriteLine(localRadio.Name)
Console.WriteLine("Send device name: " & localRadio.Name)
Else
writer.WriteLine("???")
End If
Me.Invoke(Sub()
statusText.Text = ("CONNECTED WITH: " & btClient.RemoteMachineName).ToUpper()
End Sub)
StartReadingCommands(btClient)
Catch ex As Exception
Console.WriteLine("Error on accept connection: " & ex.Message)
Me.Invoke(Sub()
statusText.Text = "Error on accept connection: " & ex.Message
End Sub)
End Try
End While
End Sub)
Catch ex As Exception
Me.Invoke(Sub()
statusText.Text = "Error on start server: " & ex.Message
End Sub)
End Try
End Sub
Private Sub StartReadingCommands(btClient As BluetoothClient)
Task.Run(Sub()
Try
Dim reader As New StreamReader(btClient.GetStream(), Encoding.UTF8)
While btClient.Connected
Try
If btClient.GetStream().DataAvailable Then
Dim command As String = reader.ReadLine()
If Not String.IsNullOrEmpty(command) Then
Console.WriteLine("Command received: " & command)
HandleBTClientCommand(command)
Else
Console.WriteLine("Empty command.")
End If
Else
Console.WriteLine("No data.")
Thread.Sleep(100)
End If
Catch ex As IOException
Console.WriteLine("Error on read command: " & ex.Message)
Exit While
Catch ex As Exception
Console.WriteLine("Error on read command: " & ex.Message)
End Try
End While
Console.WriteLine("Connection closed.")
Catch ex As Exception
Me.Invoke(Sub()
statusText.Text = "error: " & ex.Message
End Sub)
End Try
End Sub)
End Sub
Public Sub StopBTServer()
If btClient IsNot Nothing Then btClient.Close()
If btListener IsNot Nothing Then btListener.Stop()
End Sub
Private Sub HandleBTClientCommand(command As String)
Me.Invoke(Sub()
'' [...]
End Sub)
End Sub
End Class
This is my client code:
package br.com.myapplication;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "BluetoothClient";
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B31FF");
private static final int REQUEST_PERMISSIONS = 1;
private BluetoothAdapter bluetoothAdapter;
private List<BluetoothDevice> deviceList = new ArrayList<>();
private Set<String> discoveredDevices = new HashSet<>();
private ArrayAdapter<String> deviceArrayAdapter;
private OutputStream outputStream;
private InputStream inputStream;
private BluetoothSocket bluetoothSocket;
private ListView lvDevices;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initialize UI components
Button btnDiscover = findViewById(R.id.btnDiscover);
Button btnStart = findViewById(R.id.btnStart);
Button btnNext = findViewById(R.id.btnNext);
Button btnPrevious = findViewById(R.id.btnPrevious);
Button btnStop = findViewById(R.id.btnStop);
lvDevices = findViewById(R.id.lvDevices);
// Set up ArrayAdapter for ListView
deviceArrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
lvDevices.setAdapter(deviceArrayAdapter);
// Initialize BluetoothAdapter
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
Toast.makeText(this, "Not supported", Toast.LENGTH_LONG).show();
finish();
return;
}
// Check and request necessary permissions
checkPermissions();
// Set up button click listeners
btnDiscover.setOnClickListener(v -> discoverDevices());
lvDevices.setOnItemClickListener((parent, view, position, id) -> {
BluetoothDevice selectedDevice = deviceList.get(position);
connectToServer(selectedDevice);
});
// Register receiver for Bluetooth device discovery
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(receiver, filter);
}
private void checkPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
}, REQUEST_PERMISSIONS);
}
} else {
// Permissions for earlier versions
if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_ADMIN) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
}, REQUEST_PERMISSIONS);
}
}
}
private void discoverDevices() {
if (!bluetoothAdapter.isEnabled()) {
bluetoothAdapter.enable();
}
// Clear previous device list
deviceList.clear();
discoveredDevices.clear();
deviceArrayAdapter.clear();
Log.d(TAG, "Scanning devices");
bluetoothAdapter.startDiscovery();
}
// Receiver to handle found Bluetooth devices
private final BroadcastReceiver receiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device != null && !discoveredDevices.contains(device.getAddress())) {
Log.d(TAG, "Devices found: " + device.getName() + " [" + device.getAddress() + "]");
discoveredDevices.add(device.getAddress());
deviceList.add(device);
deviceArrayAdapter.add(device.getName() + "\n" + device.getAddress());
deviceArrayAdapter.notifyDataSetChanged(); // Notify adapter about data changes
}
}
}
};
private void connectToServer(BluetoothDevice serverDevice) {
new Thread(() -> {
try {
Log.d(TAG, "Trying to connect: " + serverDevice.getName());
bluetoothSocket = serverDevice.createRfcommSocketToServiceRecord(MY_UUID);
bluetoothAdapter.cancelDiscovery();
bluetoothSocket.connect();
outputStream = bluetoothSocket.getOutputStream();
inputStream = bluetoothSocket.getInputStream();
runOnUiThread(() -> Toast.makeText(this, "Connected wuth: " + serverDevice.getName(), Toast.LENGTH_SHORT).show());
Log.d(TAG, "Success connected with: " + serverDevice.getName());
} catch (IOException e) {
Log.e(TAG, "Error to connect with: " + e.getMessage());
runOnUiThread(() -> Toast.makeText(this, "Error on connect: " + e.getMessage(), Toast.LENGTH_SHORT).show());
try {
if (bluetoothSocket != null) {
bluetoothSocket.close();
}
} catch (IOException closeException) {
Log.e(TAG, "Error on close socket: " + closeException.getMessage());
}
}
}).start();
}
private void sendCommand(String command) {
if (outputStream != null) {
try {
outputStream.write((command + "\n").getBytes());
outputStream.flush();
Log.d(TAG, "Send command: " + command);
} catch (IOException e) {
Log.e(TAG, "Error os send: " + e.getMessage());
Toast.makeText(this, "Error on send: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
} else {
Log.e(TAG, "OutputStream null, no open connections");
Toast.makeText(this, "No connected", Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (bluetoothAdapter != null) {
bluetoothAdapter.cancelDiscovery();
}
unregisterReceiver(receiver);
try {
if (bluetoothSocket != null) {
bluetoothSocket.close();
}
} catch (IOException e) {
Log.e(TAG, "Error on close socket: " + e.getMessage());
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_PERMISSIONS) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Permissions granted", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Granted", Toast.LENGTH_SHORT).show();
finish();
}
}
}
}