[英]Android wifi p2p peers visibility
我正在嘗試使用wifi Direct連接2台設備,假設設備A和設備B的android> 4.1。 如果我在設備A上並且按下按鈕來搜索其他設備,則操作方式不一定總是相同的。
例如,如果我按設備A上的搜索按鈕,則即使我同時在設備B上同時按搜索按鈕,它也找不到任何東西。 因此,設備B直到它也沒有開始搜索其他設備時才可見 。
其他時候,如果我使用設備A搜索設備,即使該應用程序最近在設備B上關閉,它也會找到設備B,並且如果我嘗試連接到設備B,它也可以工作。 問題是,僅當應用程序在兩個設備上都運行時,我才想建立連接 。
有時,當設備A找到設備B並嘗試與其連接時,直到設備B開始找到設備后它才起作用。 因此,當我在設備B上開始搜索時,它會收到來自A的連接請求,但此后什么也沒有。
在其他時間,按設備A上的搜索按鈕后, 它會顯示某些設備當時未啟用wifi或超出范圍 。
這是我的代碼:
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'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實際起作用的方式:
API就是這樣工作的。 基本上為了使其他設備可見,WiFi接口需要加電並處於活動狀態,到目前為止,我已經看到它發生在設備正在進行主動發現或具有主動連接的情況下。
基本上,我想您最好的辦法是在應用運行時播發服務,並在連接時發現服務。 僅這並不是100%准確的,因此,您還可以實現從客戶端到組所有者的連接和握手,以完全檢查兩端是否正常。 如果握手失敗,請斷開連接。
我沒有直接回答的問題,基本上可能是那里不存在某些問題。 我確實知道,如果設備B處於不活動狀態,則它應該是不可見的,並且如果設備B不在API的實際“發現的對等方”列表中,則所有與它的連接嘗試都將失敗,因此可能是問題的某種組合真的發生在這里。
假設API確實確實有些時候會緩存一些結果,盡管必須承認我沒有看到此問題,但是當我關閉附近的設備時,通常會收到同級更改事件,然后服務發現未給出任何結果。任何不會真正存在的設備,因此請務必在收到Peers Changed事件后嘗試服務發現。
我有類似的問題。 我的某些設備找不到其他任何設備,但其他設備可能已與它們連接。
問題是我沒有請求位置許可。
Manifest.permission.ACCESS_COARSE_LOCATION;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.