page.title=Wi-Fi Peer-to-Peer page.tags=wireless,WifiP2pManager,Wi-Fi Direct,WiFi Direct,P2P,Wi-Fi P2P,WiFi P2P @jd:body
Wi-Fi peer-to-peer (P2P) allows Android 4.0 (API level 14) or later devices with the appropriate hardware to connect directly to each other via Wi-Fi without an intermediate access point (Android's Wi-Fi P2P framework complies with the Wi-Fi Alliance's Wi-Fi Direct™ certification program). Using these APIs, you can discover and connect to other devices when each device supports Wi-Fi P2P, then communicate over a speedy connection across distances much longer than a Bluetooth connection. This is useful for applications that share data among users, such as a multiplayer game or a photo sharing application.
The Wi-Fi P2P APIs consist of the following main parts:
You often use these three main components of the APIs together. For example, you can provide a {@link android.net.wifi.p2p.WifiP2pManager.ActionListener} to a call to {@link android.net.wifi.p2p.WifiP2pManager#discoverPeers discoverPeers()}, so that you can be notified with the {@link android.net.wifi.p2p.WifiP2pManager.ActionListener#onSuccess ActionListener.onSuccess()} and {@link android.net.wifi.p2p.WifiP2pManager.ActionListener#onFailure ActionListener.onFailure()} methods. A {@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_PEERS_CHANGED_ACTION} intent is also broadcast if the {@link android.net.wifi.p2p.WifiP2pManager#discoverPeers discoverPeers()} method discovers that the peers list has changed.
The {@link android.net.wifi.p2p.WifiP2pManager} class provides methods to allow you to interact with the Wi-Fi hardware on your device to do things like discover and connect to peers. The following actions are available:
Table 1.Wi-Fi P2P Methods
| Method | Description |
|---|---|
| {@link android.net.wifi.p2p.WifiP2pManager#initialize initialize()} | Registers the application with the Wi-Fi framework. This must be called before calling any other Wi-Fi P2P method. |
| {@link android.net.wifi.p2p.WifiP2pManager#connect connect()} | Starts a peer-to-peer connection with a device with the specified configuration. |
| {@link android.net.wifi.p2p.WifiP2pManager#cancelConnect cancelConnect()} | Cancels any ongoing peer-to-peer group negotiation. |
| {@link android.net.wifi.p2p.WifiP2pManager#requestConnectionInfo requestConnectInfo()} | Requests a device's connection information. |
| {@link android.net.wifi.p2p.WifiP2pManager#createGroup createGroup()} | Creates a peer-to-peer group with the current device as the group owner. |
| {@link android.net.wifi.p2p.WifiP2pManager#removeGroup removeGroup()} | Removes the current peer-to-peer group. |
| {@link android.net.wifi.p2p.WifiP2pManager#requestGroupInfo requestGroupInfo()} | Requests peer-to-peer group information. |
| {@link android.net.wifi.p2p.WifiP2pManager.PeerListListener#discoverPeers discoverPeers()} | Initiates peer discovery |
| {@link android.net.wifi.p2p.WifiP2pManager#requestPeers requestPeers()} | Requests the current list of discovered peers. |
{@link android.net.wifi.p2p.WifiP2pManager} methods let you pass in a listener, so that the Wi-Fi P2P framework can notify your activity of the status of a call. The available listener interfaces and the corresponding {@link android.net.wifi.p2p.WifiP2pManager} method calls that use the listeners are described in the following table:
Table 2. Wi-Fi P2P Listeners
| Listener interface | Associated actions |
|---|---|
| {@link android.net.wifi.p2p.WifiP2pManager.ActionListener} | {@link android.net.wifi.p2p.WifiP2pManager#connect connect()}, {@link android.net.wifi.p2p.WifiP2pManager#cancelConnect cancelConnect()}, {@link android.net.wifi.p2p.WifiP2pManager#createGroup createGroup()}, {@link android.net.wifi.p2p.WifiP2pManager#removeGroup removeGroup()}, and {@link android.net.wifi.p2p.WifiP2pManager.PeerListListener#discoverPeers discoverPeers()} |
| {@link android.net.wifi.p2p.WifiP2pManager.ChannelListener} | {@link android.net.wifi.p2p.WifiP2pManager#initialize initialize()} |
| {@link android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener} | {@link android.net.wifi.p2p.WifiP2pManager#requestConnectionInfo requestConnectInfo()} |
| {@link android.net.wifi.p2p.WifiP2pManager.GroupInfoListener} | {@link android.net.wifi.p2p.WifiP2pManager#requestGroupInfo requestGroupInfo()} |
| {@link android.net.wifi.p2p.WifiP2pManager.PeerListListener} | {@link android.net.wifi.p2p.WifiP2pManager#requestPeers requestPeers()} |
The Wi-Fi P2P APIs define intents that are broadcast when certain Wi-Fi P2P events happen, such as when a new peer is discovered or when a device's Wi-Fi state changes. You can register to receive these intents in your application by creating a broadcast receiver that handles these intents:
Table 3. Wi-Fi P2P Intents
| Intent | Description |
|---|---|
| {@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_CONNECTION_CHANGED_ACTION} | Broadcast when the state of the device's Wi-Fi connection changes. |
| {@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_PEERS_CHANGED_ACTION} | Broadcast when you call {@link android.net.wifi.p2p.WifiP2pManager.PeerListListener#discoverPeers discoverPeers()}. You usually want to call {@link android.net.wifi.p2p.WifiP2pManager.PeerListListener#requestPeers requestPeers()} to get an updated list of peers if you handle this intent in your application. |
| {@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_STATE_CHANGED_ACTION} | Broadcast when Wi-Fi P2P is enabled or disabled on the device. |
| {@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_THIS_DEVICE_CHANGED_ACTION} | Broadcast when a device's details have changed, such as the device's name. |
A broadcast receiver allows you to receive intents broadcast by the Android system, so that your application can respond to events that you are interested in. The basic steps for creating a broadcast receiver to handle Wi-Fi P2P intents are as follows:
{@link android.content.BroadcastReceiver#onReceive onReceive()}.
Carry out any necessary actions depending on the intent that is
received. For example, if the broadcast receiver receives a {@link
android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_PEERS_CHANGED_ACTION} intent, you can call the
{@link android.net.wifi.p2p.WifiP2pManager#requestPeers requestPeers()} method to get a list of
the currently discovered peers.The following code shows you how to create a typical broadcast receiver. The broadcast receiver takes a {@link android.net.wifi.p2p.WifiP2pManager} object and an activity as arguments and uses these two classes to appropriately carry out the needed actions when the broadcast receiver receives an intent:
/**
* A BroadcastReceiver that notifies of important Wi-Fi p2p events.
*/
public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {
private WifiP2pManager mManager;
private Channel mChannel;
private MyWiFiActivity mActivity;
public WiFiDirectBroadcastReceiver(WifiP2pManager manager, Channel channel,
MyWifiActivity 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
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
// Call WifiP2pManager.requestPeers() to get a list of current peers
} 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
}
}
}
Creating a Wi-Fi P2P application involves creating and registering a broadcast receiver for your application, discovering peers, connecting to a peer, and transferring data to a peer. The following sections describe how to do this.
Before using the Wi-Fi P2P APIs, you must ensure that your application can access the hardware and that the device supports the Wi-Fi P2P protocol. If Wi-Fi P2P is supported, you can obtain an instance of {@link android.net.wifi.p2p.WifiP2pManager}, create and register your broadcast receiver, and begin using the Wi-Fi P2P APIs.
Request permission to use the Wi-Fi hardware on the device and also declare your application to have the correct minimum SDK version in the Android manifest:
<uses-sdk android:minSdkVersion="14" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
@Override
public void onReceive(Context context, Intent intent) {
...
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
// Wifi P2P is enabled
} else {
// Wi-Fi P2P is not enabled
}
}
...
}
WifiP2pManager mManager;
Channel mChannel;
BroadcastReceiver mReceiver;
...
@Override
protected void onCreate(Bundle savedInstanceState){
...
mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mManager.initialize(this, getMainLooper(), null);
mReceiver = new WiFiDirectBroadcastReceiver(mManager, mChannel, this);
...
}
IntentFilter mIntentFilter;
...
@Override
protected void onCreate(Bundle savedInstanceState){
...
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);
}
When you have obtained a {@link android.net.wifi.p2p.WifiP2pManager.Channel} and set up a broadcast receiver, your application can make Wi-Fi P2P method calls and receive Wi-Fi P2P intents.
You can now implement your application and use the Wi-Fi P2P features by calling the methods in {@link android.net.wifi.p2p.WifiP2pManager}. The next sections describe how to do common actions such as discovering and connecting to peers.
To discover peers that are available to connect to, call {@link android.net.wifi.p2p.WifiP2pManager#discoverPeers discoverPeers()} to detect available peers that are in range. The call to this function is asynchronous and a success or failure is communicated to your application with {@link android.net.wifi.p2p.WifiP2pManager.ActionListener#onSuccess onSuccess()} and {@link android.net.wifi.p2p.WifiP2pManager.ActionListener#onFailure onFailure()} if you created a {@link android.net.wifi.p2p.WifiP2pManager.ActionListener}. The {@link android.net.wifi.p2p.WifiP2pManager.ActionListener#onSuccess onSuccess()} method only notifies you that the discovery process succeeded and does not provide any information about the actual peers that it discovered, if any:
mManager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
...
}
@Override
public void onFailure(int reasonCode) {
...
}
});
If the discovery process succeeds and detects peers, the system broadcasts the {@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_PEERS_CHANGED_ACTION} intent, which you can listen for in a broadcast receiver to obtain a list of peers. When your application receives the {@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_PEERS_CHANGED_ACTION} intent, you can request a list of the discovered peers with {@link android.net.wifi.p2p.WifiP2pManager#requestPeers requestPeers()}. The following code shows how to set this up:
PeerListListener myPeerListListener;
...
if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
// 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, myPeerListListener);
}
}
The {@link android.net.wifi.p2p.WifiP2pManager#requestPeers requestPeers()} method is also asynchronous and can notify your activity when a list of peers is available with {@link android.net.wifi.p2p.WifiP2pManager.PeerListListener#onPeersAvailable onPeersAvailable()}, which is defined in the {@link android.net.wifi.p2p.WifiP2pManager.PeerListListener} interface. The {@link android.net.wifi.p2p.WifiP2pManager.PeerListListener#onPeersAvailable onPeersAvailable()} method provides you with an {@link android.net.wifi.p2p.WifiP2pDeviceList}, which you can iterate through to find the peer that you want to connect to.
When you have figured out the device that you want to connect to after obtaining a list of possible peers, call the {@link android.net.wifi.p2p.WifiP2pManager#connect connect()} method to connect to the device. This method call requires a {@link android.net.wifi.p2p.WifiP2pConfig} object that contains the information of the device to connect to. You can be notified of a connection success or failure through the {@link android.net.wifi.p2p.WifiP2pManager.ActionListener}. The following code shows you how to create a connection to a desired device:
//obtain a peer from the WifiP2pDeviceList
WifiP2pDevice device;
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
mManager.connect(mChannel, config, new ActionListener() {
@Override
public void onSuccess() {
//success logic
}
@Override
public void onFailure(int reason) {
//failure logic
}
});
Once a connection is established, you can transfer data between the devices with sockets. The basic steps of transferring data are as follows:
The following example, modified from the Wi-Fi P2P Demo sample, shows you how to create this client-server socket communication and transfer JPEG images from a client to a server with a service. For a complete working example, compile and run the Wi-Fi P2P Demo sample.
public static class FileServerAsyncTask extends AsyncTask{ private Context context; private TextView statusText; public FileServerAsyncTask(Context context, View statusText) { this.context = context; this.statusText = (TextView) statusText; } @Override protected String doInBackground(Void... params) { try { /** * Create a server socket and wait for client connections. This * call blocks until a connection is accepted from a client */ ServerSocket serverSocket = new ServerSocket(8888); Socket client = serverSocket.accept(); /** * If this code is reached, a client has connected and transferred data * Save the input stream from the client as a JPEG file */ final File f = new File(Environment.getExternalStorageDirectory() + "/" + context.getPackageName() + "/wifip2pshared-" + System.currentTimeMillis() + ".jpg"); File dirs = new File(f.getParent()); if (!dirs.exists()) dirs.mkdirs(); f.createNewFile(); InputStream inputstream = client.getInputStream(); copyFile(inputstream, new FileOutputStream(f)); serverSocket.close(); return f.getAbsolutePath(); } catch (IOException e) { Log.e(WiFiDirectActivity.TAG, e.getMessage()); return null; } } /** * Start activity that can handle the JPEG image */ @Override protected void onPostExecute(String result) { if (result != null) { statusText.setText("File copied - " + result); Intent intent = new Intent(); intent.setAction(android.content.Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse("file://" + result), "image/*"); context.startActivity(intent); } } }
On the client, connect to the server socket with a client socket and transfer data. This example transfers a JPEG file on the client device's file system.
Context context = this.getApplicationContext();
String host;
int port;
int len;
Socket socket = new Socket();
byte buf[] = new byte[1024];
...
try {
/**
* Create a client socket with the host,
* port, and timeout information.
*/
socket.bind(null);
socket.connect((new InetSocketAddress(host, port)), 500);
/**
* Create a byte stream from a JPEG file and pipe it to the output stream
* of the socket. This data will be retrieved by the server device.
*/
OutputStream outputStream = socket.getOutputStream();
ContentResolver cr = context.getContentResolver();
InputStream inputStream = null;
inputStream = cr.openInputStream(Uri.parse("path/to/picture.jpg"));
while ((len = inputStream.read(buf)) != -1) {
outputStream.write(buf, 0, len);
}
outputStream.close();
inputStream.close();
} catch (FileNotFoundException e) {
//catch logic
} catch (IOException e) {
//catch logic
}
/**
* Clean up any open sockets when done
* transferring or if an exception occurred.
*/
finally {
if (socket != null) {
if (socket.isConnected()) {
try {
socket.close();
} catch (IOException e) {
//catch logic
}
}
}
}