I am successfully able to connect two devices and pass a string between then, very similar to the Android Studio training demo. However, when i try to connect a third device, it is not possible to do. I have tried using manager.createGroup() instead of manager.connect() but it does not work.
More specifically, I need to pass a string from the first device to the second, from the second device to the third, and from the third device back to the first. This needs to be dynamic for as many devices as are connected, so the loop would still work if there are 8 devices.
Code: Main activity
Button btnOnOff, btnDiscover, btnSend;
ListView listView;
TextView read_msg_box, connectionStatus;
EditText writeMsg;
WifiManager wifiManager;
WifiP2pManager mManager;
WifiP2pManager.Channel mChannel;
BroadcastReceiver mReceiver;
IntentFilter mIntentFilter;
//these 3 are created for getting the information about the devices
List<WifiP2pDevice> peers = new ArrayList<WifiP2pDevice>();
String[] deviceNameArray; //used to show the device name in the ListView
WifiP2pDevice[] deviceArray; //used to connect to a device
static final int MESSAGE_READ = 1; //for the handler
ServerClass serverClass;
ClientClass clientClass;
SendReceive sendReceive;
Button myTurnBtn;
// Boolean myTurn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initalWork();
exqListener();
}
//for reading the message sent
//Handler is needed to access variables from other threads
//Handler is the best way to communicate between threads
Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch(msg.what){
case MESSAGE_READ:
byte[] readBuff = (byte[]) msg.obj;
String tempMsg = new String(readBuff,0,msg.arg1);
//if tempMsg.equals("go") then show the myTurn button
if (tempMsg.equals("go")) {
myTurnBtn.setVisibility(View.VISIBLE);
Toast.makeText(MainActivity.this, "success", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "not valid", Toast.LENGTH_SHORT).show();
}
// then set MyTurn button visible
//print to screen "success"
//else
//print not valid
read_msg_box.setText(tempMsg);
break;
}
return true;
}
});
private void exqListener() {
btnOnOff.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//turn wifi off if on and on if off
//check status
if (wifiManager.isWifiEnabled()) {
//turn off wifi
wifiManager.setWifiEnabled(false);
btnOnOff.setText("ON");
} else {
//turn on wifi
wifiManager.setWifiEnabled(true);
btnOnOff.setText("OFF");
}
}
});
btnDiscover.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//discovering other devices
mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
connectionStatus.setText("Discovery Started");
}
@Override
public void onFailure(int reason) {
connectionStatus.setText("Discovery failed");
}
}); //after discovering devices, need to get the information of the nearby devices (peers)
}
});
//connect to the device that is clicked
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final WifiP2pDevice device = deviceArray[position]; //linking up the position in the ListView with deviceArray position
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
//connect to the chosen device - only tells of success or failure: need to use ConnectionInfoListener
mManager.connect(mChannel, config, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Toast.makeText(getApplicationContext(), "Connected to " + device.deviceName, Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(int reason) {
Toast.makeText(getApplicationContext(), "Not Connected", Toast.LENGTH_SHORT).show();
}
});
}
});
/* btnSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String msg = writeMsg.getText().toString();
sendReceive.write(msg.getBytes());
//
}
}); */
myTurnBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//when button is clicked. Send message to receiving device ("go")
String go = "go";
sendReceive.write(go.getBytes()); //pass the go string into the write message
//set button to be invisible
myTurnBtn.setVisibility(View.INVISIBLE);
}
});
}
private void initalWork() {
btnOnOff = findViewById(R.id.onOff);
btnDiscover = findViewById(R.id.discover);
btnSend = findViewById(R.id.sendButton);
listView = findViewById(R.id.peerListView);
read_msg_box = findViewById(R.id.readMsg);
connectionStatus = findViewById(R.id.connectionStatus);
writeMsg = findViewById(R.id.writeMsg);
myTurnBtn = findViewById(R.id.myTurnBtn);
wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE); //this class provides the API for managing wifi peer to peer connectivity
//anythign regarding the wifi p2p, this manager is used
mChannel = mManager.initialize(this, getMainLooper(), null); //a channel that connects the application to the wifi p2p framework
//most p2p operations require a channel as an argument
mReceiver = new WifiDirectBroadcastReceiver(mManager, mChannel, this);
mIntentFilter = new IntentFilter();
//add all four actions
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
// myTurnBtn =findViewById(R.id.myTurnBtn);
}
//gathering and displaying devices available
WifiP2pManager.PeerListListener peerListListener = new WifiP2pManager.PeerListListener() {
@Override
public void onPeersAvailable(WifiP2pDeviceList peerList) {
if (!peerList.getDeviceList().equals(peers)) { //if the previous list != the current list
peers.clear(); //clear the list
peers.addAll(peerList.getDeviceList()); //add all avaailable peers
//initialise deviceNameArray and deviceArray with a size of as many devices that have been found and stored in peers ArrayList
deviceNameArray = new String[peerList.getDeviceList().size()];
deviceArray = new WifiP2pDevice[peerList.getDeviceList().size()];
int index = 0;
//we have a peerList and two arrays
//using the peerList, we can add all the devices in the two arrays
for (WifiP2pDevice device : peerList.getDeviceList()) { //for each device in the peerList.getDeviceList()
//each iteration, the value of a device is stored in the device variable
deviceNameArray[index] = device.deviceName; //add all devices from deviceNameArray - storing the deviceName
deviceArray[index] = device; //add all devices from deviceArray
index++;
Log.d(TAG, "looping through devices: " +device);
//when loop is finished:
//we have name of all devices in the deviceNameArray
//we have all device objects in the deviceArray
}
//shows the list of devices in the ListView
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1
, deviceNameArray);
listView.setAdapter(adapter);
}
if (peers.size() == 0) {
Toast.makeText(getApplicationContext(), "No devices found", Toast.LENGTH_SHORT).show();
return;
}
}
};
//get information about host and client servers and manage sending and recieving data
WifiP2pManager.ConnectionInfoListener connectionInfoListener = new WifiP2pManager.ConnectionInfoListener() {
@Override
public void onConnectionInfoAvailable(WifiP2pInfo info) {
final InetAddress groupOwnerAddress = info.groupOwnerAddress; //used for sending and receiving data
//set groupOwn as the Host
if (info.groupFormed && info.isGroupOwner) {
connectionStatus.setText("Host");
myTurnBtn.setVisibility(View.VISIBLE);
serverClass = new ServerClass();
serverClass.start();
} else if (info.groupFormed) {
connectionStatus.setText("Client");
clientClass = new ClientClass(groupOwnerAddress);
clientClass.start();
}
}
};
//register the broadcast recevier
@Override
protected void onResume() {
super.onResume();
registerReceiver(mReceiver, mIntentFilter);
}
//unregister the broadcast receiver
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mReceiver);
}
public class ServerClass extends Thread {
Socket socket;
ServerSocket serverSocket;
@Override
public void run() {
try {
serverSocket = new ServerSocket(8888); //port must always be the same - can choose any number
socket = serverSocket.accept(); //socket is ready to accept message
sendReceive = new SendReceive(socket);
sendReceive.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private class SendReceive extends Thread {
private Socket socket;
private InputStream inputStream;
private OutputStream outputStream;
//constructor
public SendReceive(Socket skt) {
socket = skt;
try {
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
//override run method
@Override
public void run() {
byte[] buffer = new byte[1024]; //can choose any value
int bytes;
while (socket != null) { //always read to receive message
try {
bytes = inputStream.read(buffer); //buffer contains the message, bytes contains the number of bytes in the message
if (bytes > 0) {
handler.obtainMessage(MESSAGE_READ,bytes,-1,buffer).sendToTarget();
//handler used to deal with threading issues
//obtain message and send the data
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//method to send data
public void write(byte[] bytes) {
try {
outputStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class ClientClass extends Thread {
Socket socket;
String hostAddress;
//hostAddress is provided at runtime when ClientClass is created
public ClientClass(InetAddress hostAddress) {
this.hostAddress = hostAddress.getHostAddress();
socket = new Socket();
}
@Override
public void run() {
try {
socket.connect(new InetSocketAddress(hostAddress, 8888), 500); //same port number as server side
sendReceive = new SendReceive(socket);
sendReceive.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Broadcast Receiver:
private WifiP2pManager mManager;
private WifiP2pManager.Channel mChannel;
private MainActivity mActivity; //think about how this is used and how this can be possible with my app, on the Gameplay activity???
/**
* Constructor with args
* @param manager
* @param channel
* @param activity
*/
public WifiDirectBroadcastReceiver(WifiP2pManager manager, WifiP2pManager.Channel channel, MainActivity activity) {
mManager = manager;
mChannel = channel;
mActivity = activity;
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction(); //use this to check the current action
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) { //indicates whether Wi-Fi p2p is enabled
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1); //we will either have the value of the state or the default -1
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) { //if wifi is enabled
Toast.makeText(context, "Wifi is ON", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "Wifi is OFF", Toast.LENGTH_SHORT).show();
}
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) { //indicates that the available peer list has changed
//do something - get a list of peers by calling WifiP2pManager.requestPeers()
if (mManager!=null) {
mManager.requestPeers(mChannel, mActivity.peerListListener); //pass in peerListListener from mainActivity
}
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) { //indicates the state of the wifi p2p connectivity has changed
//do something - respond to a new connection or disconnections
if (mManager == null) {
return;
}
NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
if (networkInfo.isConnected()) {
mManager.requestConnectionInfo(mChannel,mActivity.connectionInfoListener);
} else {
mActivity.connectionStatus.setText("Device Disconnected");
}
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) { //indicates this device's configuration details have changed
//do something - respond to this device's wifi state changing
}
}
}