I am working on an Android application using WiFi Direct. The application is supposed to create a group in each device or search for peers and transfer a string to each peer, depending if the device has Internet connection or not. Also I'm able to discover the MACs of all nearby peers in case the device has Internet.
This is my code for getting the nearby devices, where groupCreated is a variable that states if this device has created a group via createGroup() or is indeed looking for peers:
private WifiP2pManager.PeerListListener peerListListener = new WifiP2pManager.PeerListListener() {
#Override
public void onPeersAvailable(WifiP2pDeviceList peerList) {
if (!groupCreated) {
Collection<WifiP2pDevice> refreshedPeers = peerList.getDeviceList();
String peerInfo = "Available peers: \n";
if (!refreshedPeers.equals(peers)) {
peers.clear();
peers.addAll(refreshedPeers);
for (WifiP2pDevice peer : peers) {
peerInfo += "\nMAC: " + peer.deviceAddress + " - Name: " + peer.deviceName;
}
TextView peerDisplay = (TextView) findViewById(R.id.peerListText);
peerDisplay.setText(peerInfo);
connectPeers();
}
if (peers.size() == 0) {
Toast.makeText(ProviderActivity.this, "No peers found!",
Toast.LENGTH_SHORT).show();
}
}
}
};
This is the code for actually connecting to the peers:
public void connectPeers(){
for (WifiP2pDevice peer : peers) {
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = peer.deviceAddress;
mManager.connect(mChannel, config, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
String host = "192.168.69.1";
int port = 8888;
int len;
Socket socket = new Socket();
String sent = "Hi!";
byte buf[] = new byte[1024];
try {
/**
* Create a client socket with the host,
* port, and timeout information.
*/
socket.bind(null);
socket.connect((new InetSocketAddress(host, port)), 1000);
/**
* Create a byte stream from a JPEG file and pipe it to the output stream
* of the socket. This data will be retrieved by the server device.
*/
OutputStream outputStream = socket.getOutputStream();
InputStream inputStream = new ByteArrayInputStream(sent.getBytes(Charset.forName("UTF-8")));
while ((len = inputStream.read(buf)) != -1) {
outputStream.write(buf, 0, len);
}
outputStream.close();
inputStream.close();
} catch (IOException e) {
System.out.println(e.toString());
}
/**
* Clean up any open sockets when done
* transferring or if an exception occurred.
*/ finally {
if (socket != null) {
if (socket.isConnected()) {
try {
socket.close();
} catch (IOException e) {
Toast.makeText(ProviderActivity.this, "Failed to close the connection!",
Toast.LENGTH_SHORT).show();
}
}
}
}
}
#Override
public void onFailure(int reason) {
Toast.makeText(ProviderActivity.this, "Failed to connect to peer!",
Toast.LENGTH_SHORT).show();
}
});
}
}
This is the client side, the server side is an async task, taken from https://developer.android.com/guide/topics/connectivity/wifip2p.html#setup in the "Transferring Data" section. Since I always connect to group owners I hardcoded the IP address Android attributes to a GO in WiFi Direct (192.168.69.1).
With this code I'm able to create the group and connect to the peers, but when I try to create a socket and transfer data, in the peers a prompt appears for the user to accept or decline the connection. In the API guide there was no user interaction involved. What am I doing wrong?
Thanks for the attention.
Similar question here.
You can track the numerous requests for this feature here.
And finally, one work around for this that i found in one of the comments in the second link i shared. Read the comments in the given code carefully.
Related
I have a client on a PC and a server on a tablet. I know the MAC addresses for both which means I do not do discoveries.
1. On the client if I use
connectString = "btspp://" + MACaddress + ":4;authenticate=false;encrypt=false;master=false";
It connects fine.
If I change the CN number (4) to anything else, it does not work. How is this number determined?
2. Everything works fine if the tablet is a Samsung with Android 5.0.2 When I use a Qunyico tablet with Android 10, it does not work. I get an error: Failed to connect; [10051] A socket operation was attempted to an unreachable network. What is the problem?
Client on PC – code taken from “Bluetooth-java-client-master”
public class IrcBluetoothClient {
private static void openConnection(String MACaddress) throws IOException {
// Tries to open the connection.
String connectString = "btspp://" + MACaddress + ":4;authenticate=false;encrypt=false;master=false";
StreamConnection connection = (StreamConnection) Connector.open(connectString);
if (connection == null) {
System.err.println("Could not open connection to address: " + MACaddress);
System.exit(1);
}
// Initializes the streams.
OutputStream output = connection.openOutputStream();
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader reader = new BufferedReader(isr);
// Starts the listening service for incoming messages.
ExecutorService service = Executors.newSingleThreadExecutor();
service.submit(new IncomingMessagesLoggingRunnable(connection));
// Main loop of the program which is not complete yet
LocalDevice localDevice = LocalDevice.getLocalDevice();
while (true) {
String toSend = reader.readLine();
byte[] toSendBytes = toSend.getBytes(StandardCharsets.US_ASCII);
output.write(toSendBytes);
System.out.println("[" + localDevice.getFriendlyName() + " - " +
localDevice.getBluetoothAddress() + "]: " + toSend);
System.exit(1);
}
Server on tablet – code taken from https://developer.android.com/guide/topics/connectivity/bluetooth
private static final UUID A_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
public BTacceptConnections( BluetoothAdapter mBluetoothAdapter) {
// Use a temporary object that is later assigned to mmServerSocket
// because mmServerSocket is final.
BluetoothServerSocket tmp = null;
try {
// A_UUID is the app's UUID string, also used by the client code.
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, A_UUID);
} catch (IOException e) {
Log.e(TAG, "Socket's listen() method failed", e);
}
mmServerSocket = tmp;
// Closes the connect socket and causes the thread to finish.
public void cancel(){
try {
mmServerSocket.close();
}catch (IOException e){
}
runFlag = 1;
}
//***********************************************************************************************
//
// This thread runs all the time listening for incoming connections.
//
public void run() {
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned.
while (runFlag == 0) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "Socket's accept() method failed", e);
break;
}
if (socket != null) { // If a connection was accepted
// A connection was accepted. Perform work associated with
// the connection in a separate thread.
// manageMyConnectedSocket(socket);
}else{
try {
mmServerSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
I know the MAC addresses for both which means I do not do discoveries.
Official Linux Bluetooth protocol stack BlueZ uses D-BUS API to establish bluetooth communication. If you check adapter-api, scanning will create device objects that you need to establish a communication which means discovering is not only done to retrieve MAC addresses only.
Your case might be the same, I would suggest doing discovery first.
hope your having a nice day . im building a Video Call application using XMPP and Jingle and direct ByteStream from phone to phone . in order to do so i noticed i need a stun server to get public ip and port of android devices and send them to the other party , im getting the public ip like this
InetAddress address = Inet4Address.getByName("stun.l.google.com");
MessageHeader sendMH = new
MessageHeader(MessageHeader.MessageHeaderType.BindingRequest);
ChangeRequest changeRequest = new ChangeRequest();
sendMH.addMessageAttribute(changeRequest);
byte[] data = sendMH.getBytes();
DatagramSocket s = new DatagramSocket(null);
localPort = s.getLocalPort();
s.setReuseAddress(true);
// s.bind(address);
DatagramPacket p = new DatagramPacket(data,
data.length,address,19302);
s.send(p);
DatagramPacket rp;
rp = new DatagramPacket(new byte[32], 32);
s.receive(rp);
MessageHeader receiveMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingResponse);
// System.out.println(receiveMH.getTransactionID().toString() + "Size:"
// + receiveMH.getTransactionID().length);
receiveMH.parseAttributes(rp.getData());
MappedAddress ma = (MappedAddress) receiveMH
.getMessageAttribute(MessageAttribute.MessageAttributeType.MappedAddress);
ip = ma.getAddress().toString();
port = ma.getPort();
Log.i("XMPP-Stabler",ma.getAddress().toString()+" "+ma.getPort());
s.close();
}catch (Exception e){
e.printStackTrace();
}
then i send the result to the other party and open up a SocketServer on this client using given port , but still i can not connect to this ServerSocket over internet , or probably i am doing some thing wrong ? can you please help me how should i use STUN or TURN results ? thanks
and here is my connecting side of Jingle just in case
otherTransport = (JingleS5BTransport)
jingle.getContents().get(0).getTransport();
ArrayList<JingleContent> contents = new ArrayList<>();
contents.add(content);
session = (JingleS5BTransportSession) JingleS5BTransportManager.getInstanceFor(connection).transportSession(new JingleSession(connection.getUser(),responderFullId,role,sessionId,contents) {
#Override
public XMPPConnection getConnection() {
return connection;
}
#Override
public void onTransportMethodFailed(String namespace) {
Log.i("XMPP-Stabler","transport method failed "+namespace);
}
});
session.setTheirProposal(otherTransport);
session.initiateOutgoingSession(new JingleTransportInitiationCallback() {
#Override
public void onSessionInitiated(BytestreamSession bytestreamSession) {
Log.i("XMPP-Stabler","ON SESSION INITIATED 2!");
Socks5BytestreamSession session = (Socks5BytestreamSession) bytestreamSession;
}
#Override
public void onException(Exception e) {
e.printStackTrace();
}
});
I have got list of paired devices of Bluetooth.Now i want to send text to that particular paired device.I have done code for that.
Below is the code:
private void init() throws IOException {
BluetoothAdapter blueAdapter = BluetoothAdapter.getDefaultAdapter();
if (blueAdapter != null) {
if (blueAdapter.isEnabled()) {
Set<BluetoothDevice> bondedDevices = blueAdapter.getBondedDevices();
if(bondedDevices.size() > 0) {
Object[] devices = (Object []) bondedDevices.toArray();
BluetoothDevice device = (BluetoothDevice) devices[position];
ParcelUuid[] uuids = device.getUuids();
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(uuids[0].getUuid());
socket.connect();
outputStream = socket.getOutputStream();
inStream = socket.getInputStream();
}
Log.e("error", "No appropriate paired devices.");
} else {
Log.e("error", "Bluetooth is disabled.");
}
}
}
public void write(String s) throws IOException {
outputStream.write(s.getBytes());
}
public void run() {
final int BUFFER_SIZE = 1024;
byte[] buffer = new byte[BUFFER_SIZE];
int bytes = 0;
int b = BUFFER_SIZE;
while (true) {
try {
bytes = inStream.read(buffer, bytes, BUFFER_SIZE - bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
But i'm getting these Error:
java.io.IOException: read failed, socket might closed or timeout, read ret: -1
04-05 10:53:41.356 5580-5580/? W/System.err: at android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:900)
04-05 10:53:41.356 5580-5580/? W/System.err: at android.bluetooth.BluetoothSocket.readInt(BluetoothSocket.java:912)
04-05 10:53:41.356 5580-5580/? W/System.err: at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:531)
So, please help me how to solve this error.
What kind of device are you trying to connect to?
-> Based on discussion: If trying to connect to another phone running Android there must be application which is accepting the connection. Working example is available from Google: BluetoothChat
You can try speeding up the connection process:
// Always cancel discovery because it will slow down a connection
mAdapter.cancelDiscovery();
Or you can try using different UUID (are there more supported)?
System.out.println(uuids);
Or you can try using insecure connection:
device.createInsecureRfcommSocketToServiceRecord(...)
BTW: Your code for reading data from inpust stream won't work very well. Take a look at example from Google Chat Application: BluetoothChatService
Good day,
I am making an Android app which sends UDP packets to Ruby server, which then forwards them to all subscribed android clients, including the original sender.
My server receives the packets, but is not able to send them or connect via UDP socket.
Server code snippet (Ruby, on Fedora 22):
SERVER_SEND_PORT = 4000
ANDROID_PORT = 7500
# Send socket
s_socket = UDPSocket.new
s_socket.setsockopt(Socket::SOL_SOCKET,Socket::SO_BROADCAST, 1)
s_socket.bind(SERVER_IP, SERVER_SEND_PORT)
# Receive socket
r_socket = UDPSocket.new
r_socket.setsockopt(Socket::SOL_SOCKET,Socket::SO_BROADCAST, 1)
r_socket.bind(SERVER_IP, RECEIVE_PORT)
$clientIPs = []
$clientPorts = []
def broadcast(data)
$clientIPs.each_with_index do |ip, index|
puts "trying to send #{data}"
s_socket.connect(ip, ANDROID_PORT) # does not pass this step
puts "connected"
s_socket.send(data, 0)
#s_socket.send(data, 0, ip, ANDROID_PORT)
puts "sent: " + data;
end
end
while true
data, client = r_socket.recvfrom(256)
puts "received: " + data
Thread.new(client) do |clientAddr|
if !$clientIPs.include? clientAddr[3]
$clientIPs << clientAddr[3]
$clientPorts << clientAddr[1]
end
broadcast(data)
end
end
Client code snippet:
private static final int LISTENING_PORT = 7500;
public void onStart() {
/* Unrelated code + Sending socket */
// Receiving Thread
new Thread(){
public void run() {
// Create receiving socket at a given port
try {
rSocket = new DatagramSocket(LISTENING_PORT);
rSocket.setBroadcast(true);
} catch (SocketException e) {
e.printStackTrace();
}
Log.d("Trace", "Created receiving socket");
while (true) {
if (rSocket != null) {
// Receive data
byte[] buf = new byte[256];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
try {
rSocket.receive(packet);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Got the packet!");
}
}
}
}.start();
}
netstat -u does not show any UDP connections in the server.
I'm facing the following problem:
I am connecting two devices via Bluetooth socket, one tablet android and a bluetooth device like reader barcode, up to now it's ok, the problem is, when a read the barcode by the bluetooth device and I send it to tablet, the bar code sometimes it's sent in two parts, for example, if I read a barcode with content "212154521212", the tablet receive "2121" and after "54521212", Anyone know tell me what should I do to avoid this?
Thanks in advanced.
My code that read the data from bluetooth device:
[code]
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private BluetoothSocket socket;
public ConnectedThread(BluetoothSocket socket) {
this.socket = socket;
InputStream tmpIn = null;
try {
tmpIn = socket.getInputStream();
} catch (IOException e) {
new LogDeErrosRodesTablet(e);
Log.e(TAG, e.getMessage());
Log.e(TAG, "Erro no construtor da classe ConnectedThread.");
}
mmInStream = tmpIn;
}
public void run() {
// continua lendo o inputstream até ocorrer um erro
while (true) {
int read = 0;
byte[] buffer = new byte[128];
do {
try {
read = mmInStream.read(buffer);
Log.e(TAG, "read: " + read);
final String data = new String(buffer, 0, read);
Log.e(TAG, "data: " + data);
//TODO
//send data only (bar code) only after read all
Bundle bundle = new Bundle();
bundle.putString(TelaInserirPedido.CODIGO_BARRAS, data);
Message message = new Message();
message.what = TelaInserirPedido.MSG_COD_BARRAS;
message.setData(bundle);
//Send a message with data
handler.sendMessage(message);
} catch(Exception ex) {
read = -1;
return;
}
Log.e(TAG, "inside while.");
} while (read > 0);
Log.e(TAG, "outside of while.");
}
}
public void cancel () {
try {
socket.close ();
} catch ( IOException e) { }
}
}
[/code]
This isn't a Bluetooth error. The Bluetooth device is sending all of the data to your application, but you are reading the stream before all of the data have been received. You could check for the amount of bytes available() on the stream before reading, if you know the exact length of the data; you could concatenate the results of all of the reads until you reach a known end point. Or you could put in an arbitrary time delay and hope the transmission completed in that time.
You would create the Bundle and Message after the while loop that collects the input string, because you don't know the entire string until that loop finishes. (Unless you are expecting multiple strings in one connection, in which case you need more complex code to handle partial numbers).
Use OutputStream.flush() to force send the all data.