1

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
        }

    }
}
  • Check this https://stackoverflow.com/questions/11251610/wifi-direct-android-4-0-with-multiple-3-devices?rq=1 – ehanoc Jun 14 '19 at 09:10
  • 1
    Hey, I have already looked at that but still cannot work out how to implement it. Right now, i can connect two clients to the host, but the message only goes between the host and the first device connected. The other device never receives the message – nuala heery Jun 14 '19 at 14:11
  • Without examples is hard to know – ehanoc Jun 14 '19 at 14:16
  • I added my code. I am trying to pass a message from the server to Client 1 and back to the server. Then i am trying to pass a message to Client 2 and then back to the server (continue for however many clients are present) and then loop this cycle. I am trying to implement taking turns in a multiplayer game. – nuala heery Jun 14 '19 at 14:49
  • @nualaheery did you find any solution probably? because I'm exactly experiencing your issue where the later device can't send or receive data. I inspected and relized that "local port" field of later device socket object is different than the other two devices. – mrzbn Jun 15 '22 at 07:51

0 Answers0