Android wifi p2p peers visibility

I am trying to connect 2 devices with direct Wi-Fi, say device A and device B with android> 4.1. If I am on device A and I press the button to search for other devices, it does not always work the same.

For example, if I press the search button on device A, it does not find anything until I press the search button on device B, even if the application works on both. Thus, device B is not displayed until it starts searching for other devices. .

In other cases, if I search for devices with device A, it finds device B, even if the application was recently closed on device B, and if I try to connect to device B, it works. The problem is that I want to establish a connection only if the application runs on both devices .

Sometimes, when device A detects device B and tries to connect to it, it does not work until device B starts to find devices. Therefore, when I start a search on device B, it receives a connection request from A, but nothing before that.

In some other cases, after clicking the search button on device A, it shows some devices in which Wi-Fi is currently not activated or is not available .

Here is my code:

MainActivity.java

import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.IntentFilter; import android.net.wifi.WpsInfo; import android.net.wifi.p2p.WifiP2pConfig; import android.net.wifi.p2p.WifiP2pDevice; import android.net.wifi.p2p.WifiP2pDeviceList; import android.net.wifi.p2p.WifiP2pGroup; import android.net.wifi.p2p.WifiP2pManager; import android.net.wifi.p2p.WifiP2pManager.ActionListener; import android.net.wifi.p2p.WifiP2pManager.Channel; import android.net.wifi.p2p.WifiP2pManager.GroupInfoListener; import android.net.wifi.p2p.WifiP2pManager.PeerListListener; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CheckedTextView; import android.widget.ListView; import android.widget.Toast; public class MainActivity extends Activity implements OnItemClickListener, PeerListListener { private WifiP2pManager mManager; private Channel mChannel; private BroadcastReceiver mReceiver; private IntentFilter mIntentFilter; private List<WifiP2pDevice> peers = new ArrayList<WifiP2pDevice>(); private List<WifiP2pDevice> peersConnect = new ArrayList<WifiP2pDevice>(); private ArrayList<String> peersName = new ArrayList<String>(); private ListView list; private Button bSearch; private Button bConnect; private Button bDisconnect; private int nSelectedDevices = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE); mChannel = mManager.initialize(this, getMainLooper(), null); try { Class<?> wifiManager = Class .forName("android.net.wifi.p2p.WifiP2pManager"); Method method = wifiManager .getMethod( "enableP2p", new Class[] { android.net.wifi.p2p.WifiP2pManager.Channel.class }); method.invoke(mManager, mChannel); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } 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); mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION); bSearch = (Button) this.findViewById(R.id.searcher); bSearch.setOnClickListener(new OnClickListener() { public void onClick (View v) { list.setVisibility(ListView.INVISIBLE); bConnect.setVisibility(View.INVISIBLE); bDisconnect.setVisibility(View.INVISIBLE); nSelectedDevices = 0; peersConnect.clear(); peers.clear(); peersName.clear(); searchDevices(); } }); bConnect = (Button) this.findViewById(R.id.connecter); bConnect.setOnClickListener(new OnClickListener() { public void onClick (View v) { bDisconnect.setVisibility(View.VISIBLE); connectDevices(); bConnect.setVisibility(View.INVISIBLE); nSelectedDevices = 0; peersConnect.clear(); } }); bDisconnect = (Button) this.findViewById(R.id.disconnecter); bDisconnect.setOnClickListener(new OnClickListener() { public void onClick (View v) { disconnectDevices(); peersConnect.clear(); bDisconnect.setVisibility(View.INVISIBLE); } }); list = (ListView) this.findViewById(R.id.list); list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); //-- text filtering list.setTextFilterEnabled(true); } /* register the broadcast receiver with the intent values to be matched */ @Override protected void onResume() { super.onResume(); mReceiver = new WifiReceiver(mManager, mChannel, this); registerReceiver(mReceiver, mIntentFilter); } /* unregister the broadcast receiver */ @Override protected void onPause() { super.onPause(); unregisterReceiver(mReceiver); } @Override protected void onDestroy() { super.onDestroy(); finish(); } public void onItemClick(AdapterView<?> parent, View v, int position, long id) { CheckedTextView item = (CheckedTextView) v; if(item.isChecked()) { nSelectedDevices++; peersConnect.add(peers.get(position)); } else { nSelectedDevices--; peersConnect.remove(peers.get(position)); } if(nSelectedDevices == 1) bConnect.setVisibility(View.VISIBLE); else if(nSelectedDevices == 0) bConnect.setVisibility(View.INVISIBLE); } @Override public void onPeersAvailable(WifiP2pDeviceList peerList) { // Out with the old, in with the new. peers.clear(); peers.addAll(peerList.getDeviceList()); getDeviceName(); list.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_checked, peersName)); list.setOnItemClickListener(this); list.setVisibility(ListView.VISIBLE); // If an AdapterView is backed by this data, notify it // of the change. For instance, if you have a ListView of available // peers, trigger an update. //((ListAdapter) getListAdapter()).notifyDataSetChanged(); if (peers.size() == 0) { return; } } private void searchDevices() { mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { //Toast.makeText(MainActivity.this, "Inizio ricerca...", Toast.LENGTH_SHORT).show(); } @Override public void onFailure(int reasonCode) { //Toast.makeText(MainActivity.this, "Ricerca fallita!", Toast.LENGTH_SHORT).show(); } }); } private void connectDevices() { for(int i = 0; i < peersConnect.size(); i++) { // Picking the first device found on the network. WifiP2pDevice device = peersConnect.get(i); WifiP2pConfig config = new WifiP2pConfig(); config.deviceAddress = device.deviceAddress; config.wps.setup = WpsInfo.PBC; mManager.connect(mChannel, config, new ActionListener() { @Override public void onSuccess() { // WiFiDirectBroadcastReceiver will notify us. Ignore for now. Toast.makeText(MainActivity.this, "Connection requested...", Toast.LENGTH_SHORT).show(); } @Override public void onFailure(int reason) { Toast.makeText(MainActivity.this, "Connect failed. Retry.", Toast.LENGTH_SHORT).show(); } }); } } public void disconnectDevices() { if (mManager != null && mChannel != null) { mManager.requestGroupInfo(mChannel, new GroupInfoListener() { @Override public void onGroupInfoAvailable(WifiP2pGroup group) { if (group != null && mManager != null && mChannel != null && group.isGroupOwner()) { mManager.removeGroup(mChannel, new ActionListener() { @Override public void onSuccess() { } @Override public void onFailure(int reason) { } }); } } }); } } private void getDeviceName() { int i = 0; peersName.clear(); while(i < peers.size()) { peersName.add(peers.get(i).deviceName); i++; } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.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(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } } 

Wifireceiver.java

 import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.net.wifi.p2p.WifiP2pManager; import android.net.wifi.p2p.WifiP2pManager.Channel; import android.widget.Toast; public class WifiReceiver extends BroadcastReceiver { private WifiP2pManager mManager; private Channel mChannel; private MainActivity mActivity; public WifiReceiver(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 if wifi is enabled/disabled System.out.println("Connection changed"); int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1); if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) { //mActivity.setIsWifiP2pEnabled(true); } else { //mActivity.setIsWifiP2pEnabled(false); } } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) { // Call WifiP2pManager.requestPeers() to get a list of current peers // 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() System.out.println("Peers changed"); if (mManager != null) { mManager.requestPeers(mChannel, mActivity); } } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) { // Respond to new connection or disconnections System.out.println("Connection changed"); } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) { // Respond to this device wifi state changing System.out.println("This device changed"); } else if (WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION.equals(action)) { // Respond to this device wifi state changing System.out.println("Search peers"); } } } 

activity_main.xml

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/linearlayout1" > <Button android:id="@+id/searcher" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_send" /> <Button android:id="@+id/connecter" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_connect" android:visibility="invisible" /> <Button android:id="@+id/disconnecter" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_disconnect" android:visibility="invisible" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/linearlayout1" > <ListView android:id="@+id/list" android:layout_width="match_parent" android:layout_height="380dp" android:layout_alignParentLeft="true" android:visibility="invisible" > </ListView> </LinearLayout> " </RelativeLayout> 

I do not understand how mManager.discoverPeers() and mManager.requestPeers() .

Thank you for attention!

+6
source share
2 answers

In fact, you have reliable observations and that the API method really works:

  • Thus, device B is not displayed until it starts searching for other devices too

The way the API works. In principle, in order to be visible to other devices, the WiFi interface must be turned on and activated, and so far I have seen how this happens when the device either makes an active discovery or has an active connection.

  1. The problem is that I want to create a connection only if the application runs on both devices

Basically, I believe that the best thing to do is to advertise the service while the application is running and open the service when connected. This is not 100% exactly one, so you can also implement a connection and a handshake from the client to the group owner to fully verify that both ends are in order and present. If the handshake fails, turn it off.

  1. Therefore, when I start a search on device B, it receives a connection request from A, but nothing until then.

I do not have a direct answer, in principle, it may be that something is wrong. I know that if device B is not active, it should not be visible, and if device B is not in the actual list of detected API peers, then all attempts to connect to it will not work, so there may be some combination of problems, it really is.

  1. it shows some devices that do not currently support Wi-Fi, or that are out of range.

Suppose the API seems to cache some results somewhat, although I must admit that I did not see this problem, I usually get peer events when I turn off a neighboring device and then the service discovery did not produce any results on any device which would not really be there, so always check for service opening after receiving the Peers Changed event.

+4
source

I had a similar problem. Some of my devices could not find other devices, but others could connect to them.

The problem was that I did not request location permissions.

 Manifest.permission.ACCESS_COARSE_LOCATION; 
0
source

Source: https://habr.com/ru/post/989639/


All Articles