java - Android wifi p2p 对端可见性

标签 java android wifi-direct

我正在尝试通过 wifi direct 连接 2 台设备,假设设备 A 和设备 B 的 android > 4.1。如果我在设备 A 上按下按钮搜索其他设备,它的行为并不总是相同。

例如,如果我按下设备 A 上的搜索按钮,它不会找到任何东西,直到我也按下设备 B 上的搜索按钮,即使该应用程序同时在两台设备上运行也是如此。 因此设备 B 在不开始搜索其他设备之前是不可见的

其他时候,如果我使用设备 A 搜索设备,它会找到设备 B,即使该应用最近在设备 B 上关闭,如果我尝试连接到设备 B,它也能正常工作。 问题是我只想在应用程序在两个设备上运行时建立连接

有时,当设备 A 发现设备 B 并尝试连接到它时,直到设备 B 开始寻找设备,它才起作用。 因此,当我开始在设备 B 上搜索时,它会收到来自 A 的连接请求,但在此之前什么也没有。

有些时候,在设备 A 上按下搜索按钮后,它会显示一些当时没有启用 wifi 或超出范围的设备

这是我的代码:

主要 Activity .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);
    }
}

无线接收器.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's wifi state changing
            System.out.println("This device changed");
        }
        else if (WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION.equals(action)) {
            // Respond to this device's 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>

我不明白 mManager.discoverPeers()mManager.requestPeers() 是如何工作的。

感谢您的关注!!

最佳答案

实际上您有有效的观察结果,这就是 API 实际工作的方式:

  1. 因此设备 B 在不开始搜索之前是不可见的 其他设备也是

这就是 API 的工作方式。基本上,为了对其他设备可见,WiFi 接口(interface)需要通电并处于 Activity 状态,到目前为止,当设备进行主动发现或进行主动连接时,我已经看到它发生了。

  1. 问题是我想建立一个 仅当应用程序在两个设备上运行时才连接

基本上,我认为您能做的最好的事情就是在应用程序运行时公布服务,并在连接时发现服务。这并不是 100% 准确的,因此,您还可以实现从客户端到组所有者的连接和握手,以全面检查两端是否正常并存在。如果握手失败,则断开连接。

  1. 因此,当我开始在设备 B 上搜索时,它会收到连接请求 来自 A,但在那之前什么都没有。

这个我没有直接的答案,基本上可能是哪里不对劲。我知道如果设备 B 不活动,它不应该是可见的,并且如果设备 B 不在 API 的实际发现对等列表中,那么所有连接尝试都会失败,所以可能是一些问题的组合真的发生在这里。

  1. 它显示了当时未启用 wifi 或超出范围的一些设备。

假设 API 确实有时会缓存一些结果,但不得不承认我没有看到这个问题,当我关闭附近的设备时,我通常会收到 peer changed 事件,然后 Service discovery 没有给出任何设备上的任何结果实际上都不会存在,因此请务必在获得 Peers Changed 事件后始终尝试服务发现。

关于java - Android wifi p2p 对端可见性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31011341/

相关文章:

java - 使用JDBC向Oracle数据库插入数据的问题

java - 生成时出错-找不到属性 'MyOpenWeatherMapApiKey'

android - 使用 PendingIntent 传递数据

android - 如何在 android 的 SDK 中启用循环样式/地形?

android - 我可以从代码中打开 WiFi-Direct 吗? API-16 (Android 4.2.2)

java - 在服务器端测试 Spring Web 服务端点?

android - 检索联系人时出现重复联系人问题

wifi-direct - 智能手机中的 Wi-Fi Direct 和移动 Ad-hoc 网络之间的区别?

java - 初始化方法以在 fragment 中注册 wifip2p 框架

java - 无法解析配置“:app:androidJdkImage”的所有文件