Home | History | Annotate | Download | only in p2p
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.net.wifi.p2p;
     18 
     19 import android.annotation.SdkConstant;
     20 import android.annotation.SdkConstant.SdkConstantType;
     21 import android.content.Context;
     22 import android.net.ConnectivityManager;
     23 import android.net.IConnectivityManager;
     24 import android.os.Binder;
     25 import android.os.IBinder;
     26 import android.os.Handler;
     27 import android.os.Looper;
     28 import android.os.Message;
     29 import android.os.RemoteException;
     30 import android.os.ServiceManager;
     31 import android.os.WorkSource;
     32 import android.os.Messenger;
     33 import android.util.Log;
     34 
     35 import com.android.internal.util.AsyncChannel;
     36 import com.android.internal.util.Protocol;
     37 
     38 import java.util.HashMap;
     39 
     40 /**
     41  * This class provides the API for managing Wi-Fi peer-to-peer connectivity. This lets an
     42  * application discover available peers, setup connection to peers and query for the list of peers.
     43  * When a p2p connection is formed over wifi, the device continues to maintain the uplink
     44  * connection over mobile or any other available network for internet connectivity on the device.
     45  *
     46  * <p> The API is asynchronous and responses to requests from an application are on listener
     47  * callbacks provided by the application. The application needs to do an initialization with
     48  * {@link #initialize} before doing any p2p operation.
     49  *
     50  * <p> Application actions {@link #discoverPeers}, {@link #connect}, {@link #cancelConnect},
     51  * {@link #createGroup} and {@link #removeGroup} need a {@link ActionListener} instance for
     52  * receiving callbacks {@link ActionListener#onSuccess} or {@link ActionListener#onFailure}.
     53  * Action callbacks indicate whether the initiation of the action was a success or a failure.
     54  * Upon failure, the reason of failure can be one of {@link #ERROR}, {@link #P2P_UNSUPPORTED}
     55  * or {@link #BUSY}.
     56  *
     57  * <p> An application can initiate discovery of peers with {@link #discoverPeers}. An initiated
     58  * discovery request from an application stays active until the device starts connecting to a peer
     59  * or forms a p2p group. The {@link ActionListener} callbacks provide feedback on whether the
     60  * discovery initiation was successful or failure. Additionally, applications can listen
     61  * to {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent action to know when the peer list changes.
     62  *
     63  * <p> When the peer list change intent {@link #WIFI_P2P_PEERS_CHANGED_ACTION} is received
     64  * or when an application needs to fetch the current list of peers, it can request the list
     65  * of peers with {@link #requestPeers}. When the peer list is available
     66  * {@link PeerListListener#onPeersAvailable} is called with the device list.
     67  *
     68  * <p> An application can initiate a connection request to a peer through {@link #connect}. See
     69  * {@link WifiP2pConfig} for details on setting up the configuration. For communication with legacy
     70  * Wi-Fi devices that do not support p2p, an app can create a group using {@link #createGroup}
     71  * which creates an access point whose details can be fetched with {@link #requestGroupInfo}.
     72 *
     73  * <p> After a successful group formation through {@link #createGroup} or through {@link #connect},
     74  * use {@link #requestConnectionInfo} to fetch the connection details. The connection info
     75  * {@link WifiP2pInfo} contains the address of the group owner
     76  * {@link WifiP2pInfo#groupOwnerAddress} and a flag {@link WifiP2pInfo#isGroupOwner} to indicate
     77  * if the current device is a p2p group owner. A p2p client can thus communicate with
     78  * the p2p group owner through a socket connection.
     79  *
     80  * <p> Android has no platform support for service discovery yet, so applications could
     81  * run a service discovery protocol to discover services on the peer-to-peer netework.
     82  *
     83  * <p class="note"><strong>Note:</strong>
     84  * Registering an application handler with {@link #initialize} requires the permissions
     85  * {@link android.Manifest.permission#ACCESS_WIFI_STATE} and
     86  * {@link android.Manifest.permission#CHANGE_WIFI_STATE} to perform any further peer-to-peer
     87  * operations.
     88  *
     89  * Get an instance of this class by calling {@link android.content.Context#getSystemService(String)
     90  * Context.getSystemService(Context.WIFI_P2P_SERVICE)}.
     91  *
     92  * {@see WifiP2pConfig}
     93  * {@see WifiP2pInfo}
     94  * {@see WifiP2pGroup}
     95  * {@see WifiP2pDevice}
     96  * {@see WifiP2pDeviceList}
     97  * {@see android.net.wifi.WpsInfo}
     98  */
     99 public class WifiP2pManager {
    100     private static final String TAG = "WifiP2pManager";
    101     /**
    102      * Broadcast intent action to indicate whether Wi-Fi p2p is enabled or disabled. An
    103      * extra {@link #EXTRA_WIFI_STATE} provides the state information as int.
    104      *
    105      * @see #EXTRA_WIFI_STATE
    106      */
    107     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    108     public static final String WIFI_P2P_STATE_CHANGED_ACTION =
    109         "android.net.wifi.p2p.STATE_CHANGED";
    110 
    111     /**
    112      * The lookup key for an int that indicates whether Wi-Fi p2p is enabled or disabled.
    113      * Retrieve it with {@link android.content.Intent#getIntExtra(String,int)}.
    114      *
    115      * @see #WIFI_P2P_STATE_DISABLED
    116      * @see #WIFI_P2P_STATE_ENABLED
    117      */
    118     public static final String EXTRA_WIFI_STATE = "wifi_p2p_state";
    119 
    120     /**
    121      * Wi-Fi p2p is disabled.
    122      *
    123      * @see #WIFI_P2P_STATE_CHANGED_ACTION
    124      */
    125     public static final int WIFI_P2P_STATE_DISABLED = 1;
    126 
    127     /**
    128      * Wi-Fi p2p is enabled.
    129      *
    130      * @see #WIFI_P2P_STATE_CHANGED_ACTION
    131      */
    132     public static final int WIFI_P2P_STATE_ENABLED = 2;
    133 
    134     /**
    135      * Broadcast intent action indicating that the state of Wi-Fi p2p connectivity
    136      * has changed. One extra {@link #EXTRA_WIFI_P2P_INFO} provides the p2p connection info in
    137      * the form of a {@link WifiP2pInfo} object. Another extra {@link #EXTRA_NETWORK_INFO} provides
    138      * the network info in the form of a {@link android.net.NetworkInfo}.
    139      *
    140      * @see #EXTRA_WIFI_P2P_INFO
    141      * @see #EXTRA_NETWORK_INFO
    142      */
    143     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    144     public static final String WIFI_P2P_CONNECTION_CHANGED_ACTION =
    145         "android.net.wifi.p2p.CONNECTION_STATE_CHANGE";
    146 
    147     /**
    148      * The lookup key for a {@link android.net.wifi.p2p.WifiP2pInfo} object
    149      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
    150      */
    151     public static final String EXTRA_WIFI_P2P_INFO = "wifiP2pInfo";
    152 
    153     /**
    154      * The lookup key for a {@link android.net.NetworkInfo} object associated with the
    155      * Wi-Fi network. Retrieve with
    156      * {@link android.content.Intent#getParcelableExtra(String)}.
    157      */
    158     public static final String EXTRA_NETWORK_INFO = "networkInfo";
    159 
    160     /**
    161      * The lookup key for a {@link android.net.LinkProperties} object associated with the
    162      * network. Retrieve with
    163      * {@link android.content.Intent#getParcelableExtra(String)}.
    164      * @hide
    165      */
    166     public static final String EXTRA_LINK_PROPERTIES = "linkProperties";
    167 
    168     /**
    169      * The lookup key for a {@link android.net.LinkCapabilities} object associated with the
    170      * network. Retrieve with
    171      * {@link android.content.Intent#getParcelableExtra(String)}.
    172      * @hide
    173      */
    174     public static final String EXTRA_LINK_CAPABILITIES = "linkCapabilities";
    175 
    176     /**
    177      * Broadcast intent action indicating that the available peer list has changed. Fetch
    178      * the changed list of peers with {@link #requestPeers}
    179      */
    180     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    181     public static final String WIFI_P2P_PEERS_CHANGED_ACTION =
    182         "android.net.wifi.p2p.PEERS_CHANGED";
    183 
    184     /**
    185      * Broadcast intent action indicating that this device details have changed.
    186      */
    187     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    188     public static final String WIFI_P2P_THIS_DEVICE_CHANGED_ACTION =
    189         "android.net.wifi.p2p.THIS_DEVICE_CHANGED";
    190 
    191     /**
    192      * The lookup key for a {@link android.net.wifi.p2p.WifiP2pDevice} object
    193      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
    194      */
    195     public static final String EXTRA_WIFI_P2P_DEVICE = "wifiP2pDevice";
    196 
    197     IWifiP2pManager mService;
    198 
    199     private static final int BASE = Protocol.BASE_WIFI_P2P_MANAGER;
    200 
    201     /** @hide */
    202     public static final int ENABLE_P2P                              = BASE + 1;
    203     /** @hide */
    204     public static final int ENABLE_P2P_FAILED                       = BASE + 2;
    205     /** @hide */
    206     public static final int ENABLE_P2P_SUCCEEDED                    = BASE + 3;
    207 
    208     /** @hide */
    209     public static final int DISABLE_P2P                             = BASE + 4;
    210     /** @hide */
    211     public static final int DISABLE_P2P_FAILED                      = BASE + 5;
    212     /** @hide */
    213     public static final int DISABLE_P2P_SUCCEEDED                   = BASE + 6;
    214 
    215     /** @hide */
    216     public static final int DISCOVER_PEERS                          = BASE + 7;
    217     /** @hide */
    218     public static final int DISCOVER_PEERS_FAILED                   = BASE + 8;
    219     /** @hide */
    220     public static final int DISCOVER_PEERS_SUCCEEDED                = BASE + 9;
    221 
    222     /** @hide */
    223     public static final int CONNECT                                 = BASE + 10;
    224     /** @hide */
    225     public static final int CONNECT_FAILED                          = BASE + 11;
    226     /** @hide */
    227     public static final int CONNECT_SUCCEEDED                       = BASE + 12;
    228 
    229     /** @hide */
    230     public static final int CANCEL_CONNECT                          = BASE + 13;
    231     /** @hide */
    232     public static final int CANCEL_CONNECT_FAILED                   = BASE + 14;
    233     /** @hide */
    234     public static final int CANCEL_CONNECT_SUCCEEDED                = BASE + 15;
    235 
    236     /** @hide */
    237     public static final int CREATE_GROUP                            = BASE + 16;
    238     /** @hide */
    239     public static final int CREATE_GROUP_FAILED                     = BASE + 17;
    240     /** @hide */
    241     public static final int CREATE_GROUP_SUCCEEDED                  = BASE + 18;
    242 
    243     /** @hide */
    244     public static final int REMOVE_GROUP                            = BASE + 19;
    245     /** @hide */
    246     public static final int REMOVE_GROUP_FAILED                     = BASE + 20;
    247     /** @hide */
    248     public static final int REMOVE_GROUP_SUCCEEDED                  = BASE + 21;
    249 
    250     /** @hide */
    251     public static final int REQUEST_PEERS                           = BASE + 22;
    252     /** @hide */
    253     public static final int RESPONSE_PEERS                          = BASE + 23;
    254 
    255     /** @hide */
    256     public static final int REQUEST_CONNECTION_INFO                 = BASE + 24;
    257     /** @hide */
    258     public static final int RESPONSE_CONNECTION_INFO                = BASE + 25;
    259 
    260     /** @hide */
    261     public static final int REQUEST_GROUP_INFO                      = BASE + 26;
    262     /** @hide */
    263     public static final int RESPONSE_GROUP_INFO                     = BASE + 27;
    264 
    265     /**
    266      * Create a new WifiP2pManager instance. Applications use
    267      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
    268      * the standard {@link android.content.Context#WIFI_P2P_SERVICE Context.WIFI_P2P_SERVICE}.
    269      * @param service the Binder interface
    270      * @hide - hide this because it takes in a parameter of type IWifiP2pManager, which
    271      * is a system private class.
    272      */
    273     public WifiP2pManager(IWifiP2pManager service) {
    274         mService = service;
    275     }
    276 
    277     /**
    278      * Passed with {@link ActionListener#onFailure}.
    279      * Indicates that the operation failed due to an internal error.
    280      */
    281     public static final int ERROR               = 0;
    282 
    283     /**
    284      * Passed with {@link ActionListener#onFailure}.
    285      * Indicates that the operation failed because p2p is unsupported on the device.
    286      */
    287     public static final int P2P_UNSUPPORTED     = 1;
    288 
    289     /**
    290      * Passed with {@link ActionListener#onFailure}.
    291      * Indicates that the operation failed because the framework is busy and
    292      * unable to service the request
    293      */
    294     public static final int BUSY                = 2;
    295 
    296     /** Interface for callback invocation when framework channel is lost */
    297     public interface ChannelListener {
    298         /**
    299          * The channel to the framework has been disconnected.
    300          * Application could try re-initializing using {@link #initialize}
    301          */
    302         public void onChannelDisconnected();
    303     }
    304 
    305     /** Interface for callback invocation on an application action */
    306     public interface ActionListener {
    307         /** The operation succeeded */
    308         public void onSuccess();
    309         /**
    310          * The operation failed
    311          * @param reason The reason for failure could be one of {@link #P2P_UNSUPPORTED},
    312          * {@link #ERROR} or {@link #BUSY}
    313          */
    314         public void onFailure(int reason);
    315     }
    316 
    317     /** Interface for callback invocation when peer list is available */
    318     public interface PeerListListener {
    319         /**
    320          * The requested peer list is available
    321          * @param peers List of available peers
    322          */
    323         public void onPeersAvailable(WifiP2pDeviceList peers);
    324     }
    325 
    326     /** Interface for callback invocation when connection info is available */
    327     public interface ConnectionInfoListener {
    328         /**
    329          * The requested connection info is available
    330          * @param info Wi-Fi p2p connection info
    331          */
    332         public void onConnectionInfoAvailable(WifiP2pInfo info);
    333     }
    334 
    335     /** Interface for callback invocation when group info is available */
    336     public interface GroupInfoListener {
    337         /**
    338          * The requested p2p group info is available
    339          * @param group Wi-Fi p2p group info
    340          */
    341         public void onGroupInfoAvailable(WifiP2pGroup group);
    342     }
    343 
    344     /**
    345      * A channel that connects the application to the Wifi p2p framework.
    346      * Most p2p operations require a Channel as an argument. An instance of Channel is obtained
    347      * by doing a call on {@link #initialize}
    348      */
    349     public static class Channel {
    350         Channel(Looper looper, ChannelListener l) {
    351             mAsyncChannel = new AsyncChannel();
    352             mHandler = new P2pHandler(looper);
    353             mChannelListener = l;
    354         }
    355         private ChannelListener mChannelListener;
    356         private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>();
    357         private Object mListenerMapLock = new Object();
    358         private int mListenerKey = 0;
    359 
    360         AsyncChannel mAsyncChannel;
    361         P2pHandler mHandler;
    362         class P2pHandler extends Handler {
    363             P2pHandler(Looper looper) {
    364                 super(looper);
    365             }
    366 
    367             @Override
    368             public void handleMessage(Message message) {
    369                 Object listener = getListener(message.arg2);
    370                 switch (message.what) {
    371                     case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
    372                         if (mChannelListener != null) {
    373                             mChannelListener.onChannelDisconnected();
    374                             mChannelListener = null;
    375                         }
    376                         break;
    377                     /* ActionListeners grouped together */
    378                     case WifiP2pManager.DISCOVER_PEERS_FAILED:
    379                     case WifiP2pManager.CONNECT_FAILED:
    380                     case WifiP2pManager.CANCEL_CONNECT_FAILED:
    381                     case WifiP2pManager.CREATE_GROUP_FAILED:
    382                     case WifiP2pManager.REMOVE_GROUP_FAILED:
    383                         if (listener != null) {
    384                             ((ActionListener) listener).onFailure(message.arg1);
    385                         }
    386                         break;
    387                     /* ActionListeners grouped together */
    388                     case WifiP2pManager.DISCOVER_PEERS_SUCCEEDED:
    389                     case WifiP2pManager.CONNECT_SUCCEEDED:
    390                     case WifiP2pManager.CANCEL_CONNECT_SUCCEEDED:
    391                     case WifiP2pManager.CREATE_GROUP_SUCCEEDED:
    392                     case WifiP2pManager.REMOVE_GROUP_SUCCEEDED:
    393                         if (listener != null) {
    394                             ((ActionListener) listener).onSuccess();
    395                         }
    396                         break;
    397                     case WifiP2pManager.RESPONSE_PEERS:
    398                         WifiP2pDeviceList peers = (WifiP2pDeviceList) message.obj;
    399                         if (listener != null) {
    400                             ((PeerListListener) listener).onPeersAvailable(peers);
    401                         }
    402                         break;
    403                     case WifiP2pManager.RESPONSE_CONNECTION_INFO:
    404                         WifiP2pInfo wifiP2pInfo = (WifiP2pInfo) message.obj;
    405                         if (listener != null) {
    406                             ((ConnectionInfoListener) listener).onConnectionInfoAvailable(wifiP2pInfo);
    407                         }
    408                         break;
    409                     case WifiP2pManager.RESPONSE_GROUP_INFO:
    410                         WifiP2pGroup group = (WifiP2pGroup) message.obj;
    411                         if (listener != null) {
    412                             ((GroupInfoListener) listener).onGroupInfoAvailable(group);
    413                         }
    414                         break;
    415                    default:
    416                         Log.d(TAG, "Ignored " + message);
    417                         break;
    418                 }
    419             }
    420         }
    421 
    422         int putListener(Object listener) {
    423             if (listener == null) return 0;
    424             int key;
    425             synchronized (mListenerMapLock) {
    426                 key = mListenerKey++;
    427                 mListenerMap.put(key, listener);
    428             }
    429             return key;
    430         }
    431 
    432         Object getListener(int key) {
    433             synchronized (mListenerMapLock) {
    434                 return mListenerMap.remove(key);
    435             }
    436         }
    437     }
    438 
    439     /**
    440      * Registers the application with the Wi-Fi framework. This function
    441      * must be the first to be called before any p2p operations are performed.
    442      *
    443      * @param srcContext is the context of the source
    444      * @param srcLooper is the Looper on which the callbacks are receivied
    445      * @param listener for callback at loss of framework communication. Can be null.
    446      * @return Channel instance that is necessary for performing any further p2p operations
    447      */
    448     public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
    449         Messenger messenger = getMessenger();
    450         if (messenger == null) return null;
    451 
    452         Channel c = new Channel(srcLooper, listener);
    453         if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger)
    454                 == AsyncChannel.STATUS_SUCCESSFUL) {
    455             return c;
    456         } else {
    457             return null;
    458         }
    459     }
    460 
    461     /**
    462      * Sends in a request to the system to enable p2p. This will pop up a dialog
    463      * to the user and upon authorization will enable p2p.
    464      * @hide
    465      */
    466     public void enableP2p(Channel c) {
    467         if (c == null) return;
    468         c.mAsyncChannel.sendMessage(ENABLE_P2P);
    469     }
    470 
    471     /**
    472      * Sends in a request to the system to disable p2p. This will pop up a dialog
    473      * to the user and upon authorization will enable p2p.
    474      * @hide
    475      */
    476     public void disableP2p(Channel c) {
    477         if (c == null) return;
    478         c.mAsyncChannel.sendMessage(DISABLE_P2P);
    479     }
    480 
    481     /**
    482      * Initiate peer discovery. A discovery process involves scanning for available Wi-Fi peers
    483      * for the purpose of establishing a connection.
    484      *
    485      * <p> The function call immediately returns after sending a discovery request
    486      * to the framework. The application is notified of a success or failure to initiate
    487      * discovery through listener callbacks {@link ActionListener#onSuccess} or
    488      * {@link ActionListener#onFailure}.
    489      *
    490      * <p> The discovery remains active until a connection is initiated or
    491      * a p2p group is formed. Register for {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent to
    492      * determine when the framework notifies of a change as peers are discovered.
    493      *
    494      * <p> Upon receiving a {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent, an application
    495      * can request for the list of peers using {@link #requestPeers}.
    496      *
    497      * @param c is the channel created at {@link #initialize}
    498      * @param listener for callbacks on success or failure. Can be null.
    499      */
    500     public void discoverPeers(Channel c, ActionListener listener) {
    501         if (c == null) return;
    502         c.mAsyncChannel.sendMessage(DISCOVER_PEERS, 0, c.putListener(listener));
    503     }
    504 
    505     /**
    506      * Start a p2p connection to a device with the specified configuration.
    507      *
    508      * <p> The function call immediately returns after sending a connection request
    509      * to the framework. The application is notified of a success or failure to initiate
    510      * connect through listener callbacks {@link ActionListener#onSuccess} or
    511      * {@link ActionListener#onFailure}.
    512      *
    513      * <p> Register for {@link #WIFI_P2P_CONNECTION_CHANGED_ACTION} intent to
    514      * determine when the framework notifies of a change in connectivity.
    515      *
    516      * <p> If the current device is not part of a p2p group, a connect request initiates
    517      * a group negotiation with the peer.
    518      *
    519      * <p> If the current device is part of an existing p2p group or has created
    520      * a p2p group with {@link #createGroup}, an invitation to join the group is sent to
    521      * the peer device.
    522      *
    523      * @param c is the channel created at {@link #initialize}
    524      * @param config options as described in {@link WifiP2pConfig} class
    525      * @param listener for callbacks on success or failure. Can be null.
    526      */
    527     public void connect(Channel c, WifiP2pConfig config, ActionListener listener) {
    528         if (c == null) return;
    529         c.mAsyncChannel.sendMessage(CONNECT, 0, c.putListener(listener), config);
    530     }
    531 
    532     /**
    533      * Cancel any ongoing p2p group negotiation
    534      *
    535      * <p> The function call immediately returns after sending a connection cancellation request
    536      * to the framework. The application is notified of a success or failure to initiate
    537      * cancellation through listener callbacks {@link ActionListener#onSuccess} or
    538      * {@link ActionListener#onFailure}.
    539      *
    540      * @param c is the channel created at {@link #initialize}
    541      * @param listener for callbacks on success or failure. Can be null.
    542      */
    543     public void cancelConnect(Channel c, ActionListener listener) {
    544         if (c == null) return;
    545         c.mAsyncChannel.sendMessage(CANCEL_CONNECT, 0, c.putListener(listener));
    546     }
    547 
    548     /**
    549      * Create a p2p group with the current device as the group owner. This essentially creates
    550      * an access point that can accept connections from legacy clients as well as other p2p
    551      * devices.
    552      *
    553      * <p class="note"><strong>Note:</strong>
    554      * This function would normally not be used unless the current device needs
    555      * to form a p2p connection with a legacy client
    556      *
    557      * <p> The function call immediately returns after sending a group creation request
    558      * to the framework. The application is notified of a success or failure to initiate
    559      * group creation through listener callbacks {@link ActionListener#onSuccess} or
    560      * {@link ActionListener#onFailure}.
    561      *
    562      * <p> Application can request for the group details with {@link #requestGroupInfo}.
    563      *
    564      * @param c is the channel created at {@link #initialize}
    565      * @param listener for callbacks on success or failure. Can be null.
    566      */
    567     public void createGroup(Channel c, ActionListener listener) {
    568         if (c == null) return;
    569         c.mAsyncChannel.sendMessage(CREATE_GROUP, 0, c.putListener(listener));
    570     }
    571 
    572     /**
    573      * Remove the current p2p group.
    574      *
    575      * <p> The function call immediately returns after sending a group removal request
    576      * to the framework. The application is notified of a success or failure to initiate
    577      * group removal through listener callbacks {@link ActionListener#onSuccess} or
    578      * {@link ActionListener#onFailure}.
    579      *
    580      * @param c is the channel created at {@link #initialize}
    581      * @param listener for callbacks on success or failure. Can be null.
    582      */
    583     public void removeGroup(Channel c, ActionListener listener) {
    584         if (c == null) return;
    585         c.mAsyncChannel.sendMessage(REMOVE_GROUP, 0, c.putListener(listener));
    586     }
    587 
    588     /**
    589      * Request the current list of peers.
    590      *
    591      * @param c is the channel created at {@link #initialize}
    592      * @param listener for callback when peer list is available. Can be null.
    593      */
    594     public void requestPeers(Channel c, PeerListListener listener) {
    595         if (c == null) return;
    596         c.mAsyncChannel.sendMessage(REQUEST_PEERS, 0, c.putListener(listener));
    597     }
    598 
    599     /**
    600      * Request device connection info.
    601      *
    602      * @param c is the channel created at {@link #initialize}
    603      * @param listener for callback when connection info is available. Can be null.
    604      */
    605     public void requestConnectionInfo(Channel c, ConnectionInfoListener listener) {
    606         if (c == null) return;
    607         c.mAsyncChannel.sendMessage(REQUEST_CONNECTION_INFO, 0, c.putListener(listener));
    608     }
    609 
    610     /**
    611      * Request p2p group info.
    612      *
    613      * @param c is the channel created at {@link #initialize}
    614      * @param listener for callback when group info is available. Can be null.
    615      */
    616     public void requestGroupInfo(Channel c, GroupInfoListener listener) {
    617         if (c == null) return;
    618         c.mAsyncChannel.sendMessage(REQUEST_GROUP_INFO, 0, c.putListener(listener));
    619     }
    620 
    621     /**
    622      * Get a reference to WifiP2pService handler. This is used to establish
    623      * an AsyncChannel communication with WifiService
    624      *
    625      * @return Messenger pointing to the WifiP2pService handler
    626      * @hide
    627      */
    628     public Messenger getMessenger() {
    629         try {
    630             return mService.getMessenger();
    631         } catch (RemoteException e) {
    632             return null;
    633         }
    634     }
    635 
    636 }
    637