Wi-Fi Direct

In a conventional wireless network, devices are connected to each other through a wireless access point. With the help of Wi-Fi Direct, devices connect to each other without the need of a wireless access point. It's similar to Bluetooth, but it is faster and the range of Wi-Fi Direct is longer. New Wi-Fi Direct APIs are introduced with Android Ice Cream Sandwich which allows us to use Wi-Fi Direct properties of Android devices.

The main class that will help us to find and connect peers is the WifiP2pManager class. We are going to use the following Listener classes during finding and connecting to peers:

  • WifiP2pManager.ActionListener
  • WifiP2pManager.ChannelListener
  • WifiP2pManager.ConnectionInfoListener
  • WifiP2pManager.PeerListListener

Finally, the following intents will help us in a Wi-Fi Direct connection:

  • WIFI_P2P_CONNECTION_CHANGED_ACTION
  • WIFI_P2P_PEERS_CHANGED_ACTION
  • WIFI_P2P_STATE_CHANGED_ACTION
  • WIFI_P2P_THIS_DEVICE_CHANGED_ACTION

In this section, we are going to learn how to use these new Wi-Fi Direct APIs with a sample application.

Sample Wi-Fi Direct application

In order to use Wi-Fi Direct APIs, we need to set the minimum SDK version to API Level 14 or more in AndroidManifest.xml. Furthermore, we need some permission to use Wi-Fi Direct APIs. The AndroidManifest.xml file should be as follows:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.chapter9"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="15" />
        <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" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".Chapter9Activity"
            android:label="@string/title_activity_chapter9" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

The first class that we need is a class that extends BroadcastReceiver and handles the intents that we listed previously in the onReceive() method. The constructor of this class should be as follows:

package com.chapter9;

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

public class Chapter9WiFiDirectBroadcastReceiver extends BroadcastReceiver {

    private WifiP2pManager manager;
    private Channel channel;
    private Chapter9Activity activity;

    public Chapter9WiFiDirectBroadcastReceiver(WifiP2pManager manager, Channel 
channel,
        Chapter9Activity activity) {
        super();
        this.manager = manager;
        this.channel = channel;
        this.activity = activity;
    }
}

As you can see in this code, we passed the Channel, WifiP2pManager, and the Activity classes to the constructor as parameters because we will need them later in the onReceive() method. We need to override the onReceive() method of BroadcastReceiver as shown in the following code block:

@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 Direct mode is enabled
              Toast.makeText(activity, "wifi direct is enabled",Toast.LENGTH_LONG).show();
            } else {
              // Wifi Direct mode is disabled
              Toast.makeText(activity, "wifi direct is disabled",Toast.LENGTH_LONG).show();
            }

        } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) 
        {

            // request peers from the wifi p2p manager
            if (manager != null) {
                manager.requestPeers(channel, (PeerListListener) activity);
            }

        } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {

            if (manager == null) {
                return;
            }

            NetworkInfo networkInfo = (NetworkInfo) intent
                    .getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);

            if (networkInfo.isConnected()) {

                // request connection info
                manager.requestConnectionInfo(channel, activity);
            } else {
                // It's a disconnect

            }
        } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {

        }
    }

In this method, we handle the received intents. Firstly, we check whether the intent is WIFI_P2P_STATE_CHANGED_ACTION. This intent is received when Wi-Fi Direct is enabled or disabled. We receive the Wi-Fi Direct status from the intent and take action according to the Wi-Fi Direct status.

Secondly, we check whether the intent is WIFI_P2P_PEERS_CHANGED_ACTION. This intent is received when the discoverPeers() method of the WifiP2pManager class is called. We get the list of the peers from the requestPeers() method of the Wifi2P2pManager class when we receive the WIFI_P2P_PEERS_CHANGED_ACTION intent.

Next, we check whether the received intent is WIFI_P2P_CONNECTION_CHANGED_ACTION. This intent is received when the Wi-Fi connection changes. We handle connections or disconnections when we receive the WIFI_P2P_CONNECTION_CHANGED_ACTION intent. We firstly get NetworkInfo from the intent to understand whether there is a connection or disconnection. If it is a connection, we call the requestConnectionInfo() method of WifiP2pManager to connect.

Lastly, we check whether the intent is WIFI_P2P_THIS_DEVICE_CHANGED_ACTION. We receive this intent when the device details have changed. We do nothing for this intent.

We have a simple user interface for this application; a layout with two buttons. The first button is to find and second button is to connect peers. The XML code of the layout is as follows:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <Button
        android:id="@+id/buttonFind"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="find" />

    <Button
        android:id="@+id/buttonConnect"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="connect" />

</LinearLayout>

The user interface will look like the following screenshot:

Sample Wi-Fi Direct application

Lastly, we need to implement the Activity class of this application. The code of the Activity class should be as follows:

package com.chapter9;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pDeviceList;
import android.net.wifi.p2p.WifiP2pInfo;
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.ChannelListener;
import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener;
import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class Chapter9Activity extends Activity implements 
ChannelListener,OnClickListener,PeerListListener,ConnectionInfoListener {

    private WifiP2pManager manager;
    private final IntentFilter intentFilter = new IntentFilter();
    private Channel channel;
    private BroadcastReceiver receiver = null;
    private Button buttonFind;
    private Button buttonConnect;
    private WifiP2pDevice device;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
        channel = manager.initialize(this, getMainLooper(), null);
        
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
        
        receiver = new Chapter9WiFiDirectBroadcastReceiver(manager, channel, this);
        registerReceiver(receiver, intentFilter);
        
        this.buttonConnect = (Button) this.findViewById(R.id.buttonConnect);
        this.buttonConnect.setOnClickListener(this);
        
        this.buttonFind = (Button)this.findViewById(R.id.buttonFind);
        this.buttonFind.setOnClickListener(this);
    }
}

The implementation is not complete currently. We will add the necessary methods step-by-step.

As you can see in this code, our Activity class implements various Listeners to handle the Wi-Fi Direct events. ConnectionInfoListener is for the callback when the connection info is available. PeerListListener is for the callback when the peer list is available. ChannelListener is for the callback when the channel is lost.

We create an intent filter and add the intents that we will check in the onReceive() method of the class that extends BroadcastReceiver.

We initialize the WifiP2pManager class by calling the initialize() method. This will register our application with the Wi-Fi network.

  1. We need to override the onChannelDisconnected() method because we implemented ChannelListener, as shown in the following code block:
    @Override
      public void onChannelDisconnected() {
        //handle the channel lost event
      }
  2. We need to implement the onPeersAvailable() method because we implemented PeerListListener, as shown in the following code block:
    @Override
      public void onPeersAvailable(WifiP2pDeviceList peerList) {
    
        for (WifiP2pDevice device : peerList.getDeviceList()) {
          this.device = device;
          break;
        }
      }

    We get the available peerList in this method. We get the first device and break the for loop. We need the device for connection.

  3. We need to implement the onConnectionInfoAvailable() method because we implemented ConnectionInfoListener, as shown in the following code block:
      @Override
      public void onConnectionInfoAvailable(WifiP2pInfo info) {
        String infoname = info.groupOwnerAddress.toString();
    
      }

    This is the place where we get the connection info and connect and send data to the peer. For instance, an AsyncTask that transfers a file could be executed here.

  4. We need to implement the onClick() method for the buttons:
      @Override
      public void onClick(View v) {
        if(v == buttonConnect)
        {
          connect(this.device);
        }
        else if(v == buttonFind)
        {
          find();
        }
        
      }

The find() and connect() methods are as follows:

public void connect(WifiP2pDevice device)
  {
    WifiP2pConfig config = new WifiP2pConfig();
    if(device != null)
    {
      config.deviceAddress = device.deviceAddress;
      manager.connect(channel, config, new ActionListener() {

          @Override
          public void onSuccess() {

            //success
          }

          @Override
          public void onFailure(int reason) {
            //fail
          }
      });
  }
    else
    {
      Toast.makeText(Chapter9Activity.this, "Couldn't connect, device is not found",

                Toast.LENGTH_SHORT).show();
    }
  }  
       public void find()
  {
    manager.discoverPeers(channel, new WifiP2pManager.ActionListener() 
       {

            @Override
            public void onSuccess() {
                Toast.makeText(Chapter9Activity.this, "Finding Peers",
                        Toast.LENGTH_SHORT).show();
       }

            @Override
            public void onFailure(int reasonCode) 
           {
                Toast.makeText(Chapter9Activity.this, "Couldnt find peers ",
                        Toast.LENGTH_SHORT).show();
            }
        });
  }

When the find button is clicked, we call the discoverPeers() method of WifiP2pManager to discover the available peers. As you will remember, calling the discoverPeers() method will cause BroadcastReceiver to receive the WIFI_P2P_PEERS_CHANGED_ACTION intent. Then we will request the peer list in BroadcastReceiver.

When the connect button is clicked, we call the connect() method of the WifiP2pManager using the device info. This starts a peer-to-peer connection with the specified device.

The sample application to introduce the Wi-Fi Direct APIs is complete with these methods.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
35.170.81.33