4

So I did my homework and looked for similar questions, I actually found one person that had the same problem two years ago... he didn't get any answer though.

The problem is the following: I'm doing the WifiP2p tutorial from android. I call discoverPeers() manually with this FloatingActionButton on the MainActivity. Then WIFI_P2P_PEERS_CHANGED_ACTION is broadcasted and received in the WifiDirectBroadcastReceiver class. There I call requestPeers(), which in turn calls onPeersAvailable() only if there is at least one discoverable peer (This makes perfect sense.)

The issue however is that once it has discovered a peer it will never go away from the list. Even if I shut down the detected device. Let me illustrate with an example:

  • 3 Devices (A,B and C), all WiFi-Direct capable.
  • Launch app on device A, keep the devices B and C shutdown.
  • Try to detect with A, nothing gets detected. No problem.
  • Turn on device B, go to WiFi-Direct settings, scan.
  • Try to detect with A, detect B. No problem.
  • Turn off device B.
  • Try to detect with A, nothing gets detected. No problem.
  • Turn on device C, go to WiFi-Direct settings, scan.
  • Try to detect with A, detect C and B. But device B is still off. Why does it still get detected? (Worst, it gets detected with a status 3, which corresponds to AVAILABLE)

This happens with any permutation of the devices' roles. So the problem is really in the code since they all behave and detect normally with the official WiFi-Direct settings window.

Here is my MainActivity:

package com.gett.wifip2ptest;

import android.content.BroadcastReceiver;
import android.content.IntentFilter;
import android.net.wifi.p2p.WifiP2pDeviceList;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;

import android.content.Context;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
import android.net.wifi.p2p.WifiP2pDevice;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements PeerListListener{

    private WifiP2pManager mManager;
    private Channel mChannel;
    private BroadcastReceiver mReceiver;

    private IntentFilter mIntentFilter;

    private List<WifiP2pDevice> peers = new ArrayList<WifiP2pDevice>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();

//                If the discovery process succeeds and detects peers, the system broadcasts the
//                WIFI_P2P_PEERS_CHANGED_ACTION intent.
                mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
                    @Override
                    public void onSuccess() {
                        Toast.makeText(MainActivity.this, "Discovery Initiated",
                                Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onFailure(int reasonCode) {
                        Toast.makeText(MainActivity.this, "Discovery Failed : " + reasonCode,
                                Toast.LENGTH_SHORT).show();
                    }
                });
            }
        });

        mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
        mChannel = mManager.initialize(this, getMainLooper(), null);
        mReceiver = new WiFiDirectBroadcastReceiver(mManager, mChannel, this);

        mIntentFilter = new IntentFilter();
        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);
    }

    /* register the broadcast receiver with the intent values to be matched */
    @Override
    protected void onResume() {
        super.onResume();
        registerReceiver(mReceiver, mIntentFilter);
    }

    /* unregister the broadcast receiver */
    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(mReceiver);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    /**
     * This function is called by requestPeers upon receiving the peers list.
     * @param peerList
     */
    @Override
    public void onPeersAvailable(WifiP2pDeviceList peerList) {
        peers.clear();
        System.out.println("Peers cleared : " + peers);

        peers.addAll(peerList.getDeviceList());

        System.out.println("Peers : " + peers);
        if (peers.size() == 0) {
            System.out.println("No devices found");
            return;
        }
    }
}

Here is WiFiDirectBroadCastReceiver:

package com.gett.wifip2ptest;

import android.content.BroadcastReceiver;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
import android.content.Context;
import android.content.Intent;

public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {

    private WifiP2pManager mManager;
    private Channel mChannel;
    private MainActivity mActivity;

    public WiFiDirectBroadcastReceiver(WifiP2pManager manager, Channel channel,
                                       MainActivity activity) {
        super();
        this.mManager = manager;
        this.mChannel = channel;
        this.mActivity = activity;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();

        if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
            // Check to see if Wi-Fi is enabled and notify appropriate activity
            int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
            if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
                // Wifi P2P is enabled
                System.out.println("Wifi Direct has been enabled.");
            } else {
                // Wi-Fi P2P is not enabled
                System.out.println("Wifi Direct is NOT enabled.");
            }
        } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
            // Call WifiP2pManager.requestPeers() to get a list of current peers
            System.out.println("Peers changed.");

            // request available peers from the wifi p2p manager. This is an
            // asynchronous call and the calling activity is notified with a
            // callback on PeerListListener.onPeersAvailable()
            if (mManager != null) {
                mManager.requestPeers(mChannel, (PeerListListener) mActivity);
            }
        } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
            // Respond to new connection or disconnections
        } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
            // Respond to this device's wifi state changing
        }
    }
}

Here is an example of two peers being detected while one of them is turned off:

02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out: Peers : [Device: Galaxy J1-2
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  deviceAddress: 2a:27:bf:3a:2e:55
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  primary type: 10-0050F204-5
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  secondary type: null
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  wps: 392
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  grpcapab: 0
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  devcapab: 37
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  status: 3
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  wfdInfo: null
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  groupownerAddress: null
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  GOdeviceName: null
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  interfaceAddress: 
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  SConnectInfo : null, Device: Test User (Galaxy J1)
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  deviceAddress: 2a:27:bf:3a:4a:8b
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  primary type: 10-0050F204-5
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  secondary type: null
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  wps: 392
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  grpcapab: 0
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  devcapab: 37
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  status: 3
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  wfdInfo: null
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  groupownerAddress: null
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  GOdeviceName: null
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  interfaceAddress: 
02-18 16:31:56.406 20833-20833/com.gett.wifip2ptest I/System.out:  SConnectInfo : null]
Community
  • 1
  • 1
Gett
  • 143
  • 1
  • 11
  • It's good you experiment with this, as I find the actual behavior for Android's WiFi Direct to be difficult to understand. Now, I'm curious what happens if you force close your App and restart it - does it still discover the absent peer? that's a hint you may be holding some object that you can try to shut down. As to solving your problem - the WifiP2pDeviceList I find the most useful in testing multiple devices. Iterate the peers from the list and look if status == WifiP2pDevice.AVAILABLE – RoundSparrow hilltx Mar 04 '16 at 12:01

3 Answers3

1

This happens because the device in which WiFi direct has been turned off does not send any broadcast to the neighboring device that it is no longer available.

I tried doing the same with the built-in WiFi Direct screen and achieved the same result as you. Discover some wifi p2p device from built-in screen, then turn off wifi in the discovered device. It does not go away until discoverPeers() is called again by the system, which is currently set (in android framework) to be called after 60 sec.

So the disabled device will disappear after 60 seconds.

This is normal behavior, probably nothing much you can do about it.

(On the contrary, a device sends a broadcast saying that it is available in the vicinity as soon as WiFi direct is turned on. That is why new devices appear instantly).

kshubham07
  • 341
  • 1
  • 3
  • 15
0

Try this in WIFI_P2P_PEERS_CHANGED_ACTION

else if(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)){
            //Log.d("wifi", "WIFI PEERS CHANGED");
            mPeers = new ArrayList<WifiP2pDevice>();
            mConfigs = new ArrayList<WifiP2pConfig>();
            if(mManager != null){
                WifiP2pManager.PeerListListener peerListListener = new WifiP2pManager.PeerListListener(){
                    @Override
                    public void onPeersAvailable(WifiP2pDeviceList peerList) {
                        mPeers.clear();
                        mPeers.addAll(peerList.getDeviceList());
                        mActivity.displayPeers(peerList);
                        //mPeers.addAll(peerList.getDeviceList());
                        for(int i=0; i < peerList.getDeviceList().size(); i++){
                            WifiP2pConfig config = new WifiP2pConfig();
                            config.deviceAddress = mPeers.get(i).deviceAddress;
                            mConfigs.add(config);
                        }
                    }
                };
                mManager.requestPeers(mChannel, peerListListener);
            }
        }

displayPeers() in MainActivity.java

 public void displayPeers(WifiP2pDeviceList peerList){
        wifiP2pArrayAdapter.clear();
        for(WifiP2pDevice peer: peerList.getDeviceList()){
            wifiP2pArrayAdapter.add(peer.deviceName + "\n" + peer.deviceAddress);
        }
    }
Tonechas
  • 13,398
  • 16
  • 46
  • 80
0

I matched the same problem as you, here is my finding:

A good answer to explain the behaviour: https://stackoverflow.com/a/25154034/3260008

And in my code I've tested the behaviour too, matched to how the answer said, if you called discoverPeers(), after 60s, the peer list will be refreshed. To my application it's acceptable.

Amos
  • 2,222
  • 1
  • 26
  • 42