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.net.wifi.WpsInfo;
     25 import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo;
     26 import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceResponse;
     27 import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
     28 import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
     29 import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
     30 import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo;
     31 import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceResponse;
     32 import android.os.Binder;
     33 import android.os.IBinder;
     34 import android.os.Handler;
     35 import android.os.Looper;
     36 import android.os.Message;
     37 import android.os.Messenger;
     38 import android.os.RemoteException;
     39 import android.os.ServiceManager;
     40 import android.os.WorkSource;
     41 import android.text.TextUtils;
     42 import android.util.Log;
     43 
     44 import com.android.internal.util.AsyncChannel;
     45 import com.android.internal.util.Protocol;
     46 
     47 import java.util.HashMap;
     48 import java.util.List;
     49 import java.util.Map;
     50 
     51 /**
     52  * This class provides the API for managing Wi-Fi peer-to-peer connectivity. This lets an
     53  * application discover available peers, setup connection to peers and query for the list of peers.
     54  * When a p2p connection is formed over wifi, the device continues to maintain the uplink
     55  * connection over mobile or any other available network for internet connectivity on the device.
     56  *
     57  * <p> The API is asynchronous and responses to requests from an application are on listener
     58  * callbacks provided by the application. The application needs to do an initialization with
     59  * {@link #initialize} before doing any p2p operation.
     60  *
     61  * <p> Most application calls need a {@link ActionListener} instance for receiving callbacks
     62  * {@link ActionListener#onSuccess} or {@link ActionListener#onFailure}. Action callbacks
     63  * indicate whether the initiation of the action was a success or a failure.
     64  * Upon failure, the reason of failure can be one of {@link #ERROR}, {@link #P2P_UNSUPPORTED}
     65  * or {@link #BUSY}.
     66  *
     67  * <p> An application can initiate discovery of peers with {@link #discoverPeers}. An initiated
     68  * discovery request from an application stays active until the device starts connecting to a peer
     69  * ,forms a p2p group or there is an explicit {@link #stopPeerDiscovery}.
     70  * Applications can listen to {@link #WIFI_P2P_DISCOVERY_CHANGED_ACTION} to know if a peer-to-peer
     71  * discovery is running or stopped. Additionally, {@link #WIFI_P2P_PEERS_CHANGED_ACTION} indicates
     72  * if the peer list has changed.
     73  *
     74  * <p> When an application needs to fetch the current list of peers, it can request the list
     75  * of peers with {@link #requestPeers}. When the peer list is available
     76  * {@link PeerListListener#onPeersAvailable} is called with the device list.
     77  *
     78  * <p> An application can initiate a connection request to a peer through {@link #connect}. See
     79  * {@link WifiP2pConfig} for details on setting up the configuration. For communication with legacy
     80  * Wi-Fi devices that do not support p2p, an app can create a group using {@link #createGroup}
     81  * which creates an access point whose details can be fetched with {@link #requestGroupInfo}.
     82  *
     83  * <p> After a successful group formation through {@link #createGroup} or through {@link #connect},
     84  * use {@link #requestConnectionInfo} to fetch the connection details. The connection info
     85  * {@link WifiP2pInfo} contains the address of the group owner
     86  * {@link WifiP2pInfo#groupOwnerAddress} and a flag {@link WifiP2pInfo#isGroupOwner} to indicate
     87  * if the current device is a p2p group owner. A p2p client can thus communicate with
     88  * the p2p group owner through a socket connection.
     89  *
     90  * <p> With peer discovery using {@link  #discoverPeers}, an application discovers the neighboring
     91  * peers, but has no good way to figure out which peer to establish a connection with. For example,
     92  * if a game application is interested in finding all the neighboring peers that are also running
     93  * the same game, it has no way to find out until after the connection is setup. Pre-association
     94  * service discovery is meant to address this issue of filtering the peers based on the running
     95  * services.
     96  *
     97  * <p>With pre-association service discovery, an application can advertise a service for a
     98  * application on a peer device prior to a connection setup between the devices.
     99  * Currently, DNS based service discovery (Bonjour) and Upnp are the higher layer protocols
    100  * supported. Get Bonjour resources at dns-sd.org and Upnp resources at upnp.org
    101  * As an example, a video application can discover a Upnp capable media renderer
    102  * prior to setting up a Wi-fi p2p connection with the device.
    103  *
    104  * <p> An application can advertise a Upnp or a Bonjour service with a call to
    105  * {@link #addLocalService}. After a local service is added,
    106  * the framework automatically responds to a peer application discovering the service prior
    107  * to establishing a p2p connection. A call to {@link #removeLocalService} removes a local
    108  * service and {@link #clearLocalServices} can be used to clear all local services.
    109  *
    110  * <p> An application that is looking for peer devices that support certain services
    111  * can do so with a call to  {@link #discoverServices}. Prior to initiating the discovery,
    112  * application can add service discovery request with a call to {@link #addServiceRequest},
    113  * remove a service discovery request with a call to {@link #removeServiceRequest} or clear
    114  * all requests with a call to {@link #clearServiceRequests}. When no service requests remain,
    115  * a previously running service discovery will stop.
    116  *
    117  * The application is notified of a result of service discovery request through listener callbacks
    118  * set through {@link #setDnsSdResponseListeners} for Bonjour or
    119  * {@link #setUpnpServiceResponseListener} for Upnp.
    120  *
    121  * <p class="note"><strong>Note:</strong>
    122  * Registering an application handler with {@link #initialize} requires the permissions
    123  * {@link android.Manifest.permission#ACCESS_WIFI_STATE} and
    124  * {@link android.Manifest.permission#CHANGE_WIFI_STATE} to perform any further peer-to-peer
    125  * operations.
    126  *
    127  * Get an instance of this class by calling {@link android.content.Context#getSystemService(String)
    128  * Context.getSystemService(Context.WIFI_P2P_SERVICE)}.
    129  *
    130  * {@see WifiP2pConfig}
    131  * {@see WifiP2pInfo}
    132  * {@see WifiP2pGroup}
    133  * {@see WifiP2pDevice}
    134  * {@see WifiP2pDeviceList}
    135  * {@see android.net.wifi.WpsInfo}
    136  */
    137 public class WifiP2pManager {
    138     private static final String TAG = "WifiP2pManager";
    139     /**
    140      * Broadcast intent action to indicate whether Wi-Fi p2p is enabled or disabled. An
    141      * extra {@link #EXTRA_WIFI_STATE} provides the state information as int.
    142      *
    143      * @see #EXTRA_WIFI_STATE
    144      */
    145     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    146     public static final String WIFI_P2P_STATE_CHANGED_ACTION =
    147         "android.net.wifi.p2p.STATE_CHANGED";
    148 
    149     /**
    150      * The lookup key for an int that indicates whether Wi-Fi p2p is enabled or disabled.
    151      * Retrieve it with {@link android.content.Intent#getIntExtra(String,int)}.
    152      *
    153      * @see #WIFI_P2P_STATE_DISABLED
    154      * @see #WIFI_P2P_STATE_ENABLED
    155      */
    156     public static final String EXTRA_WIFI_STATE = "wifi_p2p_state";
    157 
    158     /**
    159      * Wi-Fi p2p is disabled.
    160      *
    161      * @see #WIFI_P2P_STATE_CHANGED_ACTION
    162      */
    163     public static final int WIFI_P2P_STATE_DISABLED = 1;
    164 
    165     /**
    166      * Wi-Fi p2p is enabled.
    167      *
    168      * @see #WIFI_P2P_STATE_CHANGED_ACTION
    169      */
    170     public static final int WIFI_P2P_STATE_ENABLED = 2;
    171 
    172     /**
    173      * Broadcast intent action indicating that the state of Wi-Fi p2p connectivity
    174      * has changed. One extra {@link #EXTRA_WIFI_P2P_INFO} provides the p2p connection info in
    175      * the form of a {@link WifiP2pInfo} object. Another extra {@link #EXTRA_NETWORK_INFO} provides
    176      * the network info in the form of a {@link android.net.NetworkInfo}. A third extra provides
    177      * the details of the group.
    178      *
    179      * @see #EXTRA_WIFI_P2P_INFO
    180      * @see #EXTRA_NETWORK_INFO
    181      * @see #EXTRA_WIFI_P2P_GROUP
    182      */
    183     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    184     public static final String WIFI_P2P_CONNECTION_CHANGED_ACTION =
    185         "android.net.wifi.p2p.CONNECTION_STATE_CHANGE";
    186 
    187     /**
    188      * The lookup key for a {@link android.net.wifi.p2p.WifiP2pInfo} object
    189      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
    190      */
    191     public static final String EXTRA_WIFI_P2P_INFO = "wifiP2pInfo";
    192 
    193     /**
    194      * The lookup key for a {@link android.net.NetworkInfo} object associated with the
    195      * p2p network. Retrieve with
    196      * {@link android.content.Intent#getParcelableExtra(String)}.
    197      */
    198     public static final String EXTRA_NETWORK_INFO = "networkInfo";
    199 
    200     /**
    201      * The lookup key for a {@link android.net.wifi.p2p.WifiP2pGroup} object
    202      * associated with the p2p network. Retrieve with
    203      * {@link android.content.Intent#getParcelableExtra(String)}.
    204      */
    205     public static final String EXTRA_WIFI_P2P_GROUP = "p2pGroupInfo";
    206 
    207     /**
    208      * Broadcast intent action indicating that the available peer list has changed. This
    209      * can be sent as a result of peers being found, lost or updated.
    210      *
    211      * <p> An extra {@link #EXTRA_P2P_DEVICE_LIST} provides the full list of
    212      * current peers. The full list of peers can also be obtained any time with
    213      * {@link #requestPeers}.
    214      *
    215      * @see #EXTRA_P2P_DEVICE_LIST
    216      */
    217     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    218     public static final String WIFI_P2P_PEERS_CHANGED_ACTION =
    219         "android.net.wifi.p2p.PEERS_CHANGED";
    220 
    221      /**
    222       * The lookup key for a {@link android.net.wifi.p2p.WifiP2pDeviceList} object representing
    223       * the new peer list when {@link #WIFI_P2P_PEERS_CHANGED_ACTION} broadcast is sent.
    224       *
    225       * <p>Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
    226       */
    227      public static final String EXTRA_P2P_DEVICE_LIST = "wifiP2pDeviceList";
    228 
    229     /**
    230      * Broadcast intent action indicating that peer discovery has either started or stopped.
    231      * One extra {@link #EXTRA_DISCOVERY_STATE} indicates whether discovery has started
    232      * or stopped.
    233      *
    234      * <p>Note that discovery will be stopped during a connection setup. If the application tries
    235      * to re-initiate discovery during this time, it can fail.
    236      */
    237     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    238     public static final String WIFI_P2P_DISCOVERY_CHANGED_ACTION =
    239         "android.net.wifi.p2p.DISCOVERY_STATE_CHANGE";
    240 
    241     /**
    242      * The lookup key for an int that indicates whether p2p discovery has started or stopped.
    243      * Retrieve it with {@link android.content.Intent#getIntExtra(String,int)}.
    244      *
    245      * @see #WIFI_P2P_DISCOVERY_STARTED
    246      * @see #WIFI_P2P_DISCOVERY_STOPPED
    247      */
    248     public static final String EXTRA_DISCOVERY_STATE = "discoveryState";
    249 
    250     /**
    251      * p2p discovery has stopped
    252      *
    253      * @see #WIFI_P2P_DISCOVERY_CHANGED_ACTION
    254      */
    255     public static final int WIFI_P2P_DISCOVERY_STOPPED = 1;
    256 
    257     /**
    258      * p2p discovery has started
    259      *
    260      * @see #WIFI_P2P_DISCOVERY_CHANGED_ACTION
    261      */
    262     public static final int WIFI_P2P_DISCOVERY_STARTED = 2;
    263 
    264     /**
    265      * Broadcast intent action indicating that this device details have changed.
    266      */
    267     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    268     public static final String WIFI_P2P_THIS_DEVICE_CHANGED_ACTION =
    269         "android.net.wifi.p2p.THIS_DEVICE_CHANGED";
    270 
    271     /**
    272      * The lookup key for a {@link android.net.wifi.p2p.WifiP2pDevice} object
    273      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
    274      */
    275     public static final String EXTRA_WIFI_P2P_DEVICE = "wifiP2pDevice";
    276 
    277     /**
    278      * Broadcast intent action indicating that remembered persistent groups have changed.
    279      * @hide
    280      */
    281     public static final String WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION =
    282         "android.net.wifi.p2p.PERSISTENT_GROUPS_CHANGED";
    283 
    284     IWifiP2pManager mService;
    285 
    286     private static final int BASE = Protocol.BASE_WIFI_P2P_MANAGER;
    287 
    288     /** @hide */
    289     public static final int DISCOVER_PEERS                          = BASE + 1;
    290     /** @hide */
    291     public static final int DISCOVER_PEERS_FAILED                   = BASE + 2;
    292     /** @hide */
    293     public static final int DISCOVER_PEERS_SUCCEEDED                = BASE + 3;
    294 
    295     /** @hide */
    296     public static final int STOP_DISCOVERY                          = BASE + 4;
    297     /** @hide */
    298     public static final int STOP_DISCOVERY_FAILED                   = BASE + 5;
    299     /** @hide */
    300     public static final int STOP_DISCOVERY_SUCCEEDED                = BASE + 6;
    301 
    302     /** @hide */
    303     public static final int CONNECT                                 = BASE + 7;
    304     /** @hide */
    305     public static final int CONNECT_FAILED                          = BASE + 8;
    306     /** @hide */
    307     public static final int CONNECT_SUCCEEDED                       = BASE + 9;
    308 
    309     /** @hide */
    310     public static final int CANCEL_CONNECT                          = BASE + 10;
    311     /** @hide */
    312     public static final int CANCEL_CONNECT_FAILED                   = BASE + 11;
    313     /** @hide */
    314     public static final int CANCEL_CONNECT_SUCCEEDED                = BASE + 12;
    315 
    316     /** @hide */
    317     public static final int CREATE_GROUP                            = BASE + 13;
    318     /** @hide */
    319     public static final int CREATE_GROUP_FAILED                     = BASE + 14;
    320     /** @hide */
    321     public static final int CREATE_GROUP_SUCCEEDED                  = BASE + 15;
    322 
    323     /** @hide */
    324     public static final int REMOVE_GROUP                            = BASE + 16;
    325     /** @hide */
    326     public static final int REMOVE_GROUP_FAILED                     = BASE + 17;
    327     /** @hide */
    328     public static final int REMOVE_GROUP_SUCCEEDED                  = BASE + 18;
    329 
    330     /** @hide */
    331     public static final int REQUEST_PEERS                           = BASE + 19;
    332     /** @hide */
    333     public static final int RESPONSE_PEERS                          = BASE + 20;
    334 
    335     /** @hide */
    336     public static final int REQUEST_CONNECTION_INFO                 = BASE + 21;
    337     /** @hide */
    338     public static final int RESPONSE_CONNECTION_INFO                = BASE + 22;
    339 
    340     /** @hide */
    341     public static final int REQUEST_GROUP_INFO                      = BASE + 23;
    342     /** @hide */
    343     public static final int RESPONSE_GROUP_INFO                     = BASE + 24;
    344 
    345     /** @hide */
    346     public static final int ADD_LOCAL_SERVICE                       = BASE + 28;
    347     /** @hide */
    348     public static final int ADD_LOCAL_SERVICE_FAILED                = BASE + 29;
    349     /** @hide */
    350     public static final int ADD_LOCAL_SERVICE_SUCCEEDED             = BASE + 30;
    351 
    352     /** @hide */
    353     public static final int REMOVE_LOCAL_SERVICE                    = BASE + 31;
    354     /** @hide */
    355     public static final int REMOVE_LOCAL_SERVICE_FAILED             = BASE + 32;
    356     /** @hide */
    357     public static final int REMOVE_LOCAL_SERVICE_SUCCEEDED          = BASE + 33;
    358 
    359     /** @hide */
    360     public static final int CLEAR_LOCAL_SERVICES                    = BASE + 34;
    361     /** @hide */
    362     public static final int CLEAR_LOCAL_SERVICES_FAILED             = BASE + 35;
    363     /** @hide */
    364     public static final int CLEAR_LOCAL_SERVICES_SUCCEEDED          = BASE + 36;
    365 
    366     /** @hide */
    367     public static final int ADD_SERVICE_REQUEST                     = BASE + 37;
    368     /** @hide */
    369     public static final int ADD_SERVICE_REQUEST_FAILED              = BASE + 38;
    370     /** @hide */
    371     public static final int ADD_SERVICE_REQUEST_SUCCEEDED           = BASE + 39;
    372 
    373     /** @hide */
    374     public static final int REMOVE_SERVICE_REQUEST                  = BASE + 40;
    375     /** @hide */
    376     public static final int REMOVE_SERVICE_REQUEST_FAILED           = BASE + 41;
    377     /** @hide */
    378     public static final int REMOVE_SERVICE_REQUEST_SUCCEEDED        = BASE + 42;
    379 
    380     /** @hide */
    381     public static final int CLEAR_SERVICE_REQUESTS                  = BASE + 43;
    382     /** @hide */
    383     public static final int CLEAR_SERVICE_REQUESTS_FAILED           = BASE + 44;
    384     /** @hide */
    385     public static final int CLEAR_SERVICE_REQUESTS_SUCCEEDED        = BASE + 45;
    386 
    387     /** @hide */
    388     public static final int DISCOVER_SERVICES                       = BASE + 46;
    389     /** @hide */
    390     public static final int DISCOVER_SERVICES_FAILED                = BASE + 47;
    391     /** @hide */
    392     public static final int DISCOVER_SERVICES_SUCCEEDED             = BASE + 48;
    393 
    394     /** @hide */
    395     public static final int PING                                    = BASE + 49;
    396 
    397     /** @hide */
    398     public static final int RESPONSE_SERVICE                        = BASE + 50;
    399 
    400     /** @hide */
    401     public static final int SET_DEVICE_NAME                         = BASE + 51;
    402     /** @hide */
    403     public static final int SET_DEVICE_NAME_FAILED                  = BASE + 52;
    404     /** @hide */
    405     public static final int SET_DEVICE_NAME_SUCCEEDED               = BASE + 53;
    406 
    407     /** @hide */
    408     public static final int DELETE_PERSISTENT_GROUP                 = BASE + 54;
    409     /** @hide */
    410     public static final int DELETE_PERSISTENT_GROUP_FAILED          = BASE + 55;
    411     /** @hide */
    412     public static final int DELETE_PERSISTENT_GROUP_SUCCEEDED       = BASE + 56;
    413 
    414     /** @hide */
    415     public static final int REQUEST_PERSISTENT_GROUP_INFO           = BASE + 57;
    416     /** @hide */
    417     public static final int RESPONSE_PERSISTENT_GROUP_INFO          = BASE + 58;
    418 
    419     /** @hide */
    420     public static final int SET_WFD_INFO                            = BASE + 59;
    421     /** @hide */
    422     public static final int SET_WFD_INFO_FAILED                     = BASE + 60;
    423     /** @hide */
    424     public static final int SET_WFD_INFO_SUCCEEDED                  = BASE + 61;
    425 
    426     /** @hide */
    427     public static final int START_WPS                               = BASE + 62;
    428     /** @hide */
    429     public static final int START_WPS_FAILED                        = BASE + 63;
    430     /** @hide */
    431     public static final int START_WPS_SUCCEEDED                     = BASE + 64;
    432 
    433     /**
    434      * Create a new WifiP2pManager instance. Applications use
    435      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
    436      * the standard {@link android.content.Context#WIFI_P2P_SERVICE Context.WIFI_P2P_SERVICE}.
    437      * @param service the Binder interface
    438      * @hide - hide this because it takes in a parameter of type IWifiP2pManager, which
    439      * is a system private class.
    440      */
    441     public WifiP2pManager(IWifiP2pManager service) {
    442         mService = service;
    443     }
    444 
    445     /**
    446      * Passed with {@link ActionListener#onFailure}.
    447      * Indicates that the operation failed due to an internal error.
    448      */
    449     public static final int ERROR               = 0;
    450 
    451     /**
    452      * Passed with {@link ActionListener#onFailure}.
    453      * Indicates that the operation failed because p2p is unsupported on the device.
    454      */
    455     public static final int P2P_UNSUPPORTED     = 1;
    456 
    457     /**
    458      * Passed with {@link ActionListener#onFailure}.
    459      * Indicates that the operation failed because the framework is busy and
    460      * unable to service the request
    461      */
    462     public static final int BUSY                = 2;
    463 
    464     /**
    465      * Passed with {@link ActionListener#onFailure}.
    466      * Indicates that the {@link #discoverServices} failed because no service
    467      * requests are added. Use {@link #addServiceRequest} to add a service
    468      * request.
    469      */
    470     public static final int NO_SERVICE_REQUESTS = 3;
    471 
    472     /** Interface for callback invocation when framework channel is lost */
    473     public interface ChannelListener {
    474         /**
    475          * The channel to the framework has been disconnected.
    476          * Application could try re-initializing using {@link #initialize}
    477          */
    478         public void onChannelDisconnected();
    479     }
    480 
    481     /** Interface for callback invocation on an application action */
    482     public interface ActionListener {
    483         /** The operation succeeded */
    484         public void onSuccess();
    485         /**
    486          * The operation failed
    487          * @param reason The reason for failure could be one of {@link #P2P_UNSUPPORTED},
    488          * {@link #ERROR} or {@link #BUSY}
    489          */
    490         public void onFailure(int reason);
    491     }
    492 
    493     /** Interface for callback invocation when peer list is available */
    494     public interface PeerListListener {
    495         /**
    496          * The requested peer list is available
    497          * @param peers List of available peers
    498          */
    499         public void onPeersAvailable(WifiP2pDeviceList peers);
    500     }
    501 
    502     /** Interface for callback invocation when connection info is available */
    503     public interface ConnectionInfoListener {
    504         /**
    505          * The requested connection info is available
    506          * @param info Wi-Fi p2p connection info
    507          */
    508         public void onConnectionInfoAvailable(WifiP2pInfo info);
    509     }
    510 
    511     /** Interface for callback invocation when group info is available */
    512     public interface GroupInfoListener {
    513         /**
    514          * The requested p2p group info is available
    515          * @param group Wi-Fi p2p group info
    516          */
    517         public void onGroupInfoAvailable(WifiP2pGroup group);
    518     }
    519 
    520    /**
    521     * Interface for callback invocation when service discovery response other than
    522     * Upnp or Bonjour is received
    523     */
    524     public interface ServiceResponseListener {
    525 
    526         /**
    527          * The requested service response is available.
    528          *
    529          * @param protocolType protocol type. currently only
    530          * {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}.
    531          * @param responseData service discovery response data based on the requested
    532          *  service protocol type. The format depends on the service type.
    533          * @param srcDevice source device.
    534          */
    535         public void onServiceAvailable(int protocolType,
    536                 byte[] responseData, WifiP2pDevice srcDevice);
    537     }
    538 
    539     /**
    540      * Interface for callback invocation when Bonjour service discovery response
    541      * is received
    542      */
    543     public interface DnsSdServiceResponseListener {
    544 
    545         /**
    546          * The requested Bonjour service response is available.
    547          *
    548          * <p>This function is invoked when the device with the specified Bonjour
    549          * registration type returned the instance name.
    550          * @param instanceName instance name.<br>
    551          *  e.g) "MyPrinter".
    552          * @param registrationType <br>
    553          * e.g) "_ipp._tcp.local."
    554          * @param srcDevice source device.
    555          */
    556         public void onDnsSdServiceAvailable(String instanceName,
    557                 String registrationType, WifiP2pDevice srcDevice);
    558 
    559    }
    560 
    561     /**
    562      * Interface for callback invocation when Bonjour TXT record is available
    563      * for a service
    564      */
    565    public interface DnsSdTxtRecordListener {
    566         /**
    567          * The requested Bonjour service response is available.
    568          *
    569          * <p>This function is invoked when the device with the specified full
    570          * service domain service returned TXT record.
    571          *
    572          * @param fullDomainName full domain name. <br>
    573          * e.g) "MyPrinter._ipp._tcp.local.".
    574          * @param txtRecordMap TXT record data as a map of key/value pairs
    575          * @param srcDevice source device.
    576          */
    577         public void onDnsSdTxtRecordAvailable(String fullDomainName,
    578                 Map<String, String> txtRecordMap,
    579                 WifiP2pDevice srcDevice);
    580    }
    581 
    582     /**
    583      * Interface for callback invocation when upnp service discovery response
    584      * is received
    585      * */
    586     public interface UpnpServiceResponseListener {
    587 
    588         /**
    589          * The requested upnp service response is available.
    590          *
    591          * <p>This function is invoked when the specified device or service is found.
    592          *
    593          * @param uniqueServiceNames The list of unique service names.<br>
    594          * e.g) uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp-org:device:
    595          * MediaServer:1
    596          * @param srcDevice source device.
    597          */
    598         public void onUpnpServiceAvailable(List<String> uniqueServiceNames,
    599                 WifiP2pDevice srcDevice);
    600     }
    601 
    602 
    603     /** Interface for callback invocation when stored group info list is available {@hide}*/
    604     public interface PersistentGroupInfoListener {
    605         /**
    606          * The requested stored p2p group info list is available
    607          * @param groups Wi-Fi p2p group info list
    608          */
    609         public void onPersistentGroupInfoAvailable(WifiP2pGroupList groups);
    610     }
    611 
    612     /**
    613      * A channel that connects the application to the Wifi p2p framework.
    614      * Most p2p operations require a Channel as an argument. An instance of Channel is obtained
    615      * by doing a call on {@link #initialize}
    616      */
    617     public static class Channel {
    618         Channel(Context context, Looper looper, ChannelListener l) {
    619             mAsyncChannel = new AsyncChannel();
    620             mHandler = new P2pHandler(looper);
    621             mChannelListener = l;
    622             mContext = context;
    623         }
    624         private final static int INVALID_LISTENER_KEY = 0;
    625         private ChannelListener mChannelListener;
    626         private ServiceResponseListener mServRspListener;
    627         private DnsSdServiceResponseListener mDnsSdServRspListener;
    628         private DnsSdTxtRecordListener mDnsSdTxtListener;
    629         private UpnpServiceResponseListener mUpnpServRspListener;
    630         private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>();
    631         private Object mListenerMapLock = new Object();
    632         private int mListenerKey = 0;
    633 
    634         private AsyncChannel mAsyncChannel;
    635         private P2pHandler mHandler;
    636         Context mContext;
    637         class P2pHandler extends Handler {
    638             P2pHandler(Looper looper) {
    639                 super(looper);
    640             }
    641 
    642             @Override
    643             public void handleMessage(Message message) {
    644                 Object listener = getListener(message.arg2);
    645                 switch (message.what) {
    646                     case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
    647                         if (mChannelListener != null) {
    648                             mChannelListener.onChannelDisconnected();
    649                             mChannelListener = null;
    650                         }
    651                         break;
    652                     /* ActionListeners grouped together */
    653                     case DISCOVER_PEERS_FAILED:
    654                     case STOP_DISCOVERY_FAILED:
    655                     case DISCOVER_SERVICES_FAILED:
    656                     case CONNECT_FAILED:
    657                     case CANCEL_CONNECT_FAILED:
    658                     case CREATE_GROUP_FAILED:
    659                     case REMOVE_GROUP_FAILED:
    660                     case ADD_LOCAL_SERVICE_FAILED:
    661                     case REMOVE_LOCAL_SERVICE_FAILED:
    662                     case CLEAR_LOCAL_SERVICES_FAILED:
    663                     case ADD_SERVICE_REQUEST_FAILED:
    664                     case REMOVE_SERVICE_REQUEST_FAILED:
    665                     case CLEAR_SERVICE_REQUESTS_FAILED:
    666                     case SET_DEVICE_NAME_FAILED:
    667                     case DELETE_PERSISTENT_GROUP_FAILED:
    668                     case SET_WFD_INFO_FAILED:
    669                     case START_WPS_FAILED:
    670                         if (listener != null) {
    671                             ((ActionListener) listener).onFailure(message.arg1);
    672                         }
    673                         break;
    674                     /* ActionListeners grouped together */
    675                     case DISCOVER_PEERS_SUCCEEDED:
    676                     case STOP_DISCOVERY_SUCCEEDED:
    677                     case DISCOVER_SERVICES_SUCCEEDED:
    678                     case CONNECT_SUCCEEDED:
    679                     case CANCEL_CONNECT_SUCCEEDED:
    680                     case CREATE_GROUP_SUCCEEDED:
    681                     case REMOVE_GROUP_SUCCEEDED:
    682                     case ADD_LOCAL_SERVICE_SUCCEEDED:
    683                     case REMOVE_LOCAL_SERVICE_SUCCEEDED:
    684                     case CLEAR_LOCAL_SERVICES_SUCCEEDED:
    685                     case ADD_SERVICE_REQUEST_SUCCEEDED:
    686                     case REMOVE_SERVICE_REQUEST_SUCCEEDED:
    687                     case CLEAR_SERVICE_REQUESTS_SUCCEEDED:
    688                     case SET_DEVICE_NAME_SUCCEEDED:
    689                     case DELETE_PERSISTENT_GROUP_SUCCEEDED:
    690                     case SET_WFD_INFO_SUCCEEDED:
    691                     case START_WPS_SUCCEEDED:
    692                         if (listener != null) {
    693                             ((ActionListener) listener).onSuccess();
    694                         }
    695                         break;
    696                     case RESPONSE_PEERS:
    697                         WifiP2pDeviceList peers = (WifiP2pDeviceList) message.obj;
    698                         if (listener != null) {
    699                             ((PeerListListener) listener).onPeersAvailable(peers);
    700                         }
    701                         break;
    702                     case RESPONSE_CONNECTION_INFO:
    703                         WifiP2pInfo wifiP2pInfo = (WifiP2pInfo) message.obj;
    704                         if (listener != null) {
    705                             ((ConnectionInfoListener) listener).onConnectionInfoAvailable(wifiP2pInfo);
    706                         }
    707                         break;
    708                     case RESPONSE_GROUP_INFO:
    709                         WifiP2pGroup group = (WifiP2pGroup) message.obj;
    710                         if (listener != null) {
    711                             ((GroupInfoListener) listener).onGroupInfoAvailable(group);
    712                         }
    713                         break;
    714                     case RESPONSE_SERVICE:
    715                         WifiP2pServiceResponse resp = (WifiP2pServiceResponse) message.obj;
    716                         handleServiceResponse(resp);
    717                         break;
    718                     case RESPONSE_PERSISTENT_GROUP_INFO:
    719                         WifiP2pGroupList groups = (WifiP2pGroupList) message.obj;
    720                         if (listener != null) {
    721                             ((PersistentGroupInfoListener) listener).
    722                                 onPersistentGroupInfoAvailable(groups);
    723                         }
    724                         break;
    725                    default:
    726                         Log.d(TAG, "Ignored " + message);
    727                         break;
    728                 }
    729             }
    730         }
    731 
    732         private void handleServiceResponse(WifiP2pServiceResponse resp) {
    733             if (resp instanceof WifiP2pDnsSdServiceResponse) {
    734                 handleDnsSdServiceResponse((WifiP2pDnsSdServiceResponse)resp);
    735             } else if (resp instanceof WifiP2pUpnpServiceResponse) {
    736                 if (mUpnpServRspListener != null) {
    737                     handleUpnpServiceResponse((WifiP2pUpnpServiceResponse)resp);
    738                 }
    739             } else {
    740                 if (mServRspListener != null) {
    741                     mServRspListener.onServiceAvailable(resp.getServiceType(),
    742                             resp.getRawData(), resp.getSrcDevice());
    743                 }
    744             }
    745         }
    746 
    747         private void handleUpnpServiceResponse(WifiP2pUpnpServiceResponse resp) {
    748             mUpnpServRspListener.onUpnpServiceAvailable(resp.getUniqueServiceNames(),
    749                     resp.getSrcDevice());
    750         }
    751 
    752         private void handleDnsSdServiceResponse(WifiP2pDnsSdServiceResponse resp) {
    753             if (resp.getDnsType() == WifiP2pDnsSdServiceInfo.DNS_TYPE_PTR) {
    754                 if (mDnsSdServRspListener != null) {
    755                     mDnsSdServRspListener.onDnsSdServiceAvailable(
    756                             resp.getInstanceName(),
    757                             resp.getDnsQueryName(),
    758                             resp.getSrcDevice());
    759                 }
    760             } else if (resp.getDnsType() == WifiP2pDnsSdServiceInfo.DNS_TYPE_TXT) {
    761                 if (mDnsSdTxtListener != null) {
    762                     mDnsSdTxtListener.onDnsSdTxtRecordAvailable(
    763                             resp.getDnsQueryName(),
    764                             resp.getTxtRecord(),
    765                             resp.getSrcDevice());
    766                 }
    767             } else {
    768                 Log.e(TAG, "Unhandled resp " + resp);
    769             }
    770         }
    771 
    772         private int putListener(Object listener) {
    773             if (listener == null) return INVALID_LISTENER_KEY;
    774             int key;
    775             synchronized (mListenerMapLock) {
    776                 do {
    777                     key = mListenerKey++;
    778                 } while (key == INVALID_LISTENER_KEY);
    779                 mListenerMap.put(key, listener);
    780             }
    781             return key;
    782         }
    783 
    784         private Object getListener(int key) {
    785             if (key == INVALID_LISTENER_KEY) return null;
    786             synchronized (mListenerMapLock) {
    787                 return mListenerMap.remove(key);
    788             }
    789         }
    790     }
    791 
    792     private static void checkChannel(Channel c) {
    793         if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
    794     }
    795 
    796     private static void checkServiceInfo(WifiP2pServiceInfo info) {
    797         if (info == null) throw new IllegalArgumentException("service info is null");
    798     }
    799 
    800     private static void checkServiceRequest(WifiP2pServiceRequest req) {
    801         if (req == null) throw new IllegalArgumentException("service request is null");
    802     }
    803 
    804     private static void checkP2pConfig(WifiP2pConfig c) {
    805         if (c == null) throw new IllegalArgumentException("config cannot be null");
    806         if (TextUtils.isEmpty(c.deviceAddress)) {
    807             throw new IllegalArgumentException("deviceAddress cannot be empty");
    808         }
    809     }
    810 
    811     /**
    812      * Registers the application with the Wi-Fi framework. This function
    813      * must be the first to be called before any p2p operations are performed.
    814      *
    815      * @param srcContext is the context of the source
    816      * @param srcLooper is the Looper on which the callbacks are receivied
    817      * @param listener for callback at loss of framework communication. Can be null.
    818      * @return Channel instance that is necessary for performing any further p2p operations
    819      */
    820     public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
    821         Messenger messenger = getMessenger();
    822         if (messenger == null) return null;
    823 
    824         Channel c = new Channel(srcContext, srcLooper, listener);
    825         if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger)
    826                 == AsyncChannel.STATUS_SUCCESSFUL) {
    827             return c;
    828         } else {
    829             return null;
    830         }
    831     }
    832 
    833     /**
    834      * Initiate peer discovery. A discovery process involves scanning for available Wi-Fi peers
    835      * for the purpose of establishing a connection.
    836      *
    837      * <p> The function call immediately returns after sending a discovery request
    838      * to the framework. The application is notified of a success or failure to initiate
    839      * discovery through listener callbacks {@link ActionListener#onSuccess} or
    840      * {@link ActionListener#onFailure}.
    841      *
    842      * <p> The discovery remains active until a connection is initiated or
    843      * a p2p group is formed. Register for {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent to
    844      * determine when the framework notifies of a change as peers are discovered.
    845      *
    846      * <p> Upon receiving a {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent, an application
    847      * can request for the list of peers using {@link #requestPeers}.
    848      *
    849      * @param c is the channel created at {@link #initialize}
    850      * @param listener for callbacks on success or failure. Can be null.
    851      */
    852     public void discoverPeers(Channel c, ActionListener listener) {
    853         checkChannel(c);
    854         c.mAsyncChannel.sendMessage(DISCOVER_PEERS, 0, c.putListener(listener));
    855     }
    856 
    857    /**
    858      * Stop an ongoing peer discovery
    859      *
    860      * <p> The function call immediately returns after sending a stop request
    861      * to the framework. The application is notified of a success or failure to initiate
    862      * stop through listener callbacks {@link ActionListener#onSuccess} or
    863      * {@link ActionListener#onFailure}.
    864      *
    865      * @param c is the channel created at {@link #initialize}
    866      * @param listener for callbacks on success or failure. Can be null.
    867      */
    868     public void stopPeerDiscovery(Channel c, ActionListener listener) {
    869         checkChannel(c);
    870         c.mAsyncChannel.sendMessage(STOP_DISCOVERY, 0, c.putListener(listener));
    871     }
    872 
    873     /**
    874      * Start a p2p connection to a device with the specified configuration.
    875      *
    876      * <p> The function call immediately returns after sending a connection request
    877      * to the framework. The application is notified of a success or failure to initiate
    878      * connect through listener callbacks {@link ActionListener#onSuccess} or
    879      * {@link ActionListener#onFailure}.
    880      *
    881      * <p> Register for {@link #WIFI_P2P_CONNECTION_CHANGED_ACTION} intent to
    882      * determine when the framework notifies of a change in connectivity.
    883      *
    884      * <p> If the current device is not part of a p2p group, a connect request initiates
    885      * a group negotiation with the peer.
    886      *
    887      * <p> If the current device is part of an existing p2p group or has created
    888      * a p2p group with {@link #createGroup}, an invitation to join the group is sent to
    889      * the peer device.
    890      *
    891      * @param c is the channel created at {@link #initialize}
    892      * @param config options as described in {@link WifiP2pConfig} class
    893      * @param listener for callbacks on success or failure. Can be null.
    894      */
    895     public void connect(Channel c, WifiP2pConfig config, ActionListener listener) {
    896         checkChannel(c);
    897         checkP2pConfig(config);
    898         c.mAsyncChannel.sendMessage(CONNECT, 0, c.putListener(listener), config);
    899     }
    900 
    901     /**
    902      * Cancel any ongoing p2p group negotiation
    903      *
    904      * <p> The function call immediately returns after sending a connection cancellation request
    905      * to the framework. The application is notified of a success or failure to initiate
    906      * cancellation through listener callbacks {@link ActionListener#onSuccess} or
    907      * {@link ActionListener#onFailure}.
    908      *
    909      * @param c is the channel created at {@link #initialize}
    910      * @param listener for callbacks on success or failure. Can be null.
    911      */
    912     public void cancelConnect(Channel c, ActionListener listener) {
    913         checkChannel(c);
    914         c.mAsyncChannel.sendMessage(CANCEL_CONNECT, 0, c.putListener(listener));
    915     }
    916 
    917     /**
    918      * Create a p2p group with the current device as the group owner. This essentially creates
    919      * an access point that can accept connections from legacy clients as well as other p2p
    920      * devices.
    921      *
    922      * <p class="note"><strong>Note:</strong>
    923      * This function would normally not be used unless the current device needs
    924      * to form a p2p connection with a legacy client
    925      *
    926      * <p> The function call immediately returns after sending a group creation request
    927      * to the framework. The application is notified of a success or failure to initiate
    928      * group creation through listener callbacks {@link ActionListener#onSuccess} or
    929      * {@link ActionListener#onFailure}.
    930      *
    931      * <p> Application can request for the group details with {@link #requestGroupInfo}.
    932      *
    933      * @param c is the channel created at {@link #initialize}
    934      * @param listener for callbacks on success or failure. Can be null.
    935      */
    936     public void createGroup(Channel c, ActionListener listener) {
    937         checkChannel(c);
    938         c.mAsyncChannel.sendMessage(CREATE_GROUP, WifiP2pGroup.PERSISTENT_NET_ID,
    939                 c.putListener(listener));
    940     }
    941 
    942     /**
    943      * Remove the current p2p group.
    944      *
    945      * <p> The function call immediately returns after sending a group removal request
    946      * to the framework. The application is notified of a success or failure to initiate
    947      * group removal through listener callbacks {@link ActionListener#onSuccess} or
    948      * {@link ActionListener#onFailure}.
    949      *
    950      * @param c is the channel created at {@link #initialize}
    951      * @param listener for callbacks on success or failure. Can be null.
    952      */
    953     public void removeGroup(Channel c, ActionListener listener) {
    954         checkChannel(c);
    955         c.mAsyncChannel.sendMessage(REMOVE_GROUP, 0, c.putListener(listener));
    956     }
    957 
    958     /**
    959      * Start a Wi-Fi Protected Setup (WPS) session.
    960      *
    961      * <p> The function call immediately returns after sending a request to start a
    962      * WPS session. Currently, this is only valid if the current device is running
    963      * as a group owner to allow any new clients to join the group. The application
    964      * is notified of a success or failure to initiate WPS through listener callbacks
    965      * {@link ActionListener#onSuccess} or {@link ActionListener#onFailure}.
    966      * @hide
    967      */
    968     public void startWps(Channel c, WpsInfo wps, ActionListener listener) {
    969         checkChannel(c);
    970         c.mAsyncChannel.sendMessage(START_WPS, 0, c.putListener(listener), wps);
    971     }
    972 
    973     /**
    974      * Register a local service for service discovery. If a local service is registered,
    975      * the framework automatically responds to a service discovery request from a peer.
    976      *
    977      * <p> The function call immediately returns after sending a request to add a local
    978      * service to the framework. The application is notified of a success or failure to
    979      * add service through listener callbacks {@link ActionListener#onSuccess} or
    980      * {@link ActionListener#onFailure}.
    981      *
    982      * <p>The service information is set through {@link WifiP2pServiceInfo}.<br>
    983      * or its subclass calls  {@link WifiP2pUpnpServiceInfo#newInstance} or
    984      *  {@link WifiP2pDnsSdServiceInfo#newInstance} for a Upnp or Bonjour service
    985      * respectively
    986      *
    987      * <p>The service information can be cleared with calls to
    988      *  {@link #removeLocalService} or {@link #clearLocalServices}.
    989      *
    990      * @param c is the channel created at {@link #initialize}
    991      * @param servInfo is a local service information.
    992      * @param listener for callbacks on success or failure. Can be null.
    993      */
    994     public void addLocalService(Channel c, WifiP2pServiceInfo servInfo, ActionListener listener) {
    995         checkChannel(c);
    996         checkServiceInfo(servInfo);
    997         c.mAsyncChannel.sendMessage(ADD_LOCAL_SERVICE, 0, c.putListener(listener), servInfo);
    998     }
    999 
   1000     /**
   1001      * Remove a registered local service added with {@link #addLocalService}
   1002      *
   1003      * <p> The function call immediately returns after sending a request to remove a
   1004      * local service to the framework. The application is notified of a success or failure to
   1005      * add service through listener callbacks {@link ActionListener#onSuccess} or
   1006      * {@link ActionListener#onFailure}.
   1007      *
   1008      * @param c is the channel created at {@link #initialize}
   1009      * @param servInfo is the local service information.
   1010      * @param listener for callbacks on success or failure. Can be null.
   1011      */
   1012     public void removeLocalService(Channel c, WifiP2pServiceInfo servInfo,
   1013             ActionListener listener) {
   1014         checkChannel(c);
   1015         checkServiceInfo(servInfo);
   1016         c.mAsyncChannel.sendMessage(REMOVE_LOCAL_SERVICE, 0, c.putListener(listener), servInfo);
   1017     }
   1018 
   1019     /**
   1020      * Clear all registered local services of service discovery.
   1021      *
   1022      * <p> The function call immediately returns after sending a request to clear all
   1023      * local services to the framework. The application is notified of a success or failure to
   1024      * add service through listener callbacks {@link ActionListener#onSuccess} or
   1025      * {@link ActionListener#onFailure}.
   1026      *
   1027      * @param c is the channel created at {@link #initialize}
   1028      * @param listener for callbacks on success or failure. Can be null.
   1029      */
   1030     public void clearLocalServices(Channel c, ActionListener listener) {
   1031         checkChannel(c);
   1032         c.mAsyncChannel.sendMessage(CLEAR_LOCAL_SERVICES, 0, c.putListener(listener));
   1033     }
   1034 
   1035     /**
   1036      * Register a callback to be invoked on receiving service discovery response.
   1037      * Used only for vendor specific protocol right now. For Bonjour or Upnp, use
   1038      * {@link #setDnsSdResponseListeners} or {@link #setUpnpServiceResponseListener}
   1039      * respectively.
   1040      *
   1041      * <p> see {@link #discoverServices} for the detail.
   1042      *
   1043      * @param c is the channel created at {@link #initialize}
   1044      * @param listener for callbacks on receiving service discovery response.
   1045      */
   1046     public void setServiceResponseListener(Channel c,
   1047             ServiceResponseListener listener) {
   1048         checkChannel(c);
   1049         c.mServRspListener = listener;
   1050     }
   1051 
   1052     /**
   1053      * Register a callback to be invoked on receiving Bonjour service discovery
   1054      * response.
   1055      *
   1056      * <p> see {@link #discoverServices} for the detail.
   1057      *
   1058      * @param c
   1059      * @param servListener is for listening to a Bonjour service response
   1060      * @param txtListener is for listening to a Bonjour TXT record response
   1061      */
   1062     public void setDnsSdResponseListeners(Channel c,
   1063             DnsSdServiceResponseListener servListener, DnsSdTxtRecordListener txtListener) {
   1064         checkChannel(c);
   1065         c.mDnsSdServRspListener = servListener;
   1066         c.mDnsSdTxtListener = txtListener;
   1067     }
   1068 
   1069     /**
   1070      * Register a callback to be invoked on receiving upnp service discovery
   1071      * response.
   1072      *
   1073      * <p> see {@link #discoverServices} for the detail.
   1074      *
   1075      * @param c is the channel created at {@link #initialize}
   1076      * @param listener for callbacks on receiving service discovery response.
   1077      */
   1078     public void setUpnpServiceResponseListener(Channel c,
   1079             UpnpServiceResponseListener listener) {
   1080         checkChannel(c);
   1081         c.mUpnpServRspListener = listener;
   1082     }
   1083 
   1084     /**
   1085      * Initiate service discovery. A discovery process involves scanning for
   1086      * requested services for the purpose of establishing a connection to a peer
   1087      * that supports an available service.
   1088      *
   1089      * <p> The function call immediately returns after sending a request to start service
   1090      * discovery to the framework. The application is notified of a success or failure to initiate
   1091      * discovery through listener callbacks {@link ActionListener#onSuccess} or
   1092      * {@link ActionListener#onFailure}.
   1093      *
   1094      * <p> The services to be discovered are specified with calls to {@link #addServiceRequest}.
   1095      *
   1096      * <p>The application is notified of the response against the service discovery request
   1097      * through listener callbacks registered by {@link #setServiceResponseListener} or
   1098      * {@link #setDnsSdResponseListeners}, or {@link #setUpnpServiceResponseListener}.
   1099      *
   1100      * @param c is the channel created at {@link #initialize}
   1101      * @param listener for callbacks on success or failure. Can be null.
   1102      */
   1103     public void discoverServices(Channel c, ActionListener listener) {
   1104         checkChannel(c);
   1105         c.mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, c.putListener(listener));
   1106     }
   1107 
   1108     /**
   1109      * Add a service discovery request.
   1110      *
   1111      * <p> The function call immediately returns after sending a request to add service
   1112      * discovery request to the framework. The application is notified of a success or failure to
   1113      * add service through listener callbacks {@link ActionListener#onSuccess} or
   1114      * {@link ActionListener#onFailure}.
   1115      *
   1116      * <p>After service discovery request is added, you can initiate service discovery by
   1117      * {@link #discoverServices}.
   1118      *
   1119      * <p>The added service requests can be cleared with calls to
   1120      * {@link #removeServiceRequest(Channel, WifiP2pServiceRequest, ActionListener)} or
   1121      * {@link #clearServiceRequests(Channel, ActionListener)}.
   1122      *
   1123      * @param c is the channel created at {@link #initialize}
   1124      * @param req is the service discovery request.
   1125      * @param listener for callbacks on success or failure. Can be null.
   1126      */
   1127     public void addServiceRequest(Channel c,
   1128             WifiP2pServiceRequest req, ActionListener listener) {
   1129         checkChannel(c);
   1130         checkServiceRequest(req);
   1131         c.mAsyncChannel.sendMessage(ADD_SERVICE_REQUEST, 0,
   1132                 c.putListener(listener), req);
   1133     }
   1134 
   1135     /**
   1136      * Remove a specified service discovery request added with {@link #addServiceRequest}
   1137      *
   1138      * <p> The function call immediately returns after sending a request to remove service
   1139      * discovery request to the framework. The application is notified of a success or failure to
   1140      * add service through listener callbacks {@link ActionListener#onSuccess} or
   1141      * {@link ActionListener#onFailure}.
   1142      *
   1143      * @param c is the channel created at {@link #initialize}
   1144      * @param req is the service discovery request.
   1145      * @param listener for callbacks on success or failure. Can be null.
   1146      */
   1147     public void removeServiceRequest(Channel c, WifiP2pServiceRequest req,
   1148             ActionListener listener) {
   1149         checkChannel(c);
   1150         checkServiceRequest(req);
   1151         c.mAsyncChannel.sendMessage(REMOVE_SERVICE_REQUEST, 0,
   1152                 c.putListener(listener), req);
   1153     }
   1154 
   1155     /**
   1156      * Clear all registered service discovery requests.
   1157      *
   1158      * <p> The function call immediately returns after sending a request to clear all
   1159      * service discovery requests to the framework. The application is notified of a success
   1160      * or failure to add service through listener callbacks {@link ActionListener#onSuccess} or
   1161      * {@link ActionListener#onFailure}.
   1162      *
   1163      * @param c is the channel created at {@link #initialize}
   1164      * @param listener for callbacks on success or failure. Can be null.
   1165      */
   1166     public void clearServiceRequests(Channel c, ActionListener listener) {
   1167         checkChannel(c);
   1168         c.mAsyncChannel.sendMessage(CLEAR_SERVICE_REQUESTS,
   1169                 0, c.putListener(listener));
   1170     }
   1171 
   1172     /**
   1173      * Request the current list of peers.
   1174      *
   1175      * @param c is the channel created at {@link #initialize}
   1176      * @param listener for callback when peer list is available. Can be null.
   1177      */
   1178     public void requestPeers(Channel c, PeerListListener listener) {
   1179         checkChannel(c);
   1180         c.mAsyncChannel.sendMessage(REQUEST_PEERS, 0, c.putListener(listener));
   1181     }
   1182 
   1183     /**
   1184      * Request device connection info.
   1185      *
   1186      * @param c is the channel created at {@link #initialize}
   1187      * @param listener for callback when connection info is available. Can be null.
   1188      */
   1189     public void requestConnectionInfo(Channel c, ConnectionInfoListener listener) {
   1190         checkChannel(c);
   1191         c.mAsyncChannel.sendMessage(REQUEST_CONNECTION_INFO, 0, c.putListener(listener));
   1192     }
   1193 
   1194     /**
   1195      * Request p2p group info.
   1196      *
   1197      * @param c is the channel created at {@link #initialize}
   1198      * @param listener for callback when group info is available. Can be null.
   1199      */
   1200     public void requestGroupInfo(Channel c, GroupInfoListener listener) {
   1201         checkChannel(c);
   1202         c.mAsyncChannel.sendMessage(REQUEST_GROUP_INFO, 0, c.putListener(listener));
   1203     }
   1204 
   1205     /**
   1206      * Set p2p device name.
   1207      * @hide
   1208      * @param c is the channel created at {@link #initialize}
   1209      * @param listener for callback when group info is available. Can be null.
   1210      */
   1211     public void setDeviceName(Channel c, String devName, ActionListener listener) {
   1212         checkChannel(c);
   1213         WifiP2pDevice d = new WifiP2pDevice();
   1214         d.deviceName = devName;
   1215         c.mAsyncChannel.sendMessage(SET_DEVICE_NAME, 0, c.putListener(listener), d);
   1216     }
   1217 
   1218     /** @hide */
   1219     public void setWFDInfo(
   1220             Channel c, WifiP2pWfdInfo wfdInfo,
   1221             ActionListener listener) {
   1222         checkChannel(c);
   1223         c.mAsyncChannel.sendMessage(SET_WFD_INFO, 0, c.putListener(listener), wfdInfo);
   1224     }
   1225 
   1226 
   1227     /**
   1228      * Delete a stored persistent group from the system settings.
   1229      *
   1230      * <p> The function call immediately returns after sending a persistent group removal request
   1231      * to the framework. The application is notified of a success or failure to initiate
   1232      * group removal through listener callbacks {@link ActionListener#onSuccess} or
   1233      * {@link ActionListener#onFailure}.
   1234      *
   1235      * <p>The persistent p2p group list stored in the system can be obtained by
   1236      * {@link #requestPersistentGroupInfo(Channel, PersistentGroupInfoListener)} and
   1237      *  a network id can be obtained by {@link WifiP2pGroup#getNetworkId()}.
   1238      *
   1239      * @param c is the channel created at {@link #initialize}
   1240      * @param netId he network id of the p2p group.
   1241      * @param listener for callbacks on success or failure. Can be null.
   1242      * @hide
   1243      */
   1244     public void deletePersistentGroup(Channel c, int netId, ActionListener listener) {
   1245         checkChannel(c);
   1246         c.mAsyncChannel.sendMessage(DELETE_PERSISTENT_GROUP, netId, c.putListener(listener));
   1247     }
   1248 
   1249     /**
   1250      * Request a list of all the persistent p2p groups stored in system.
   1251      *
   1252      * @param c is the channel created at {@link #initialize}
   1253      * @param listener for callback when persistent group info list is available. Can be null.
   1254      * @hide
   1255      */
   1256     public void requestPersistentGroupInfo(Channel c, PersistentGroupInfoListener listener) {
   1257         checkChannel(c);
   1258         c.mAsyncChannel.sendMessage(REQUEST_PERSISTENT_GROUP_INFO, 0, c.putListener(listener));
   1259     }
   1260 
   1261     /** @hide */
   1262     public static final int MIRACAST_DISABLED = 0;
   1263     /** @hide */
   1264     public static final int MIRACAST_SOURCE   = 1;
   1265     /** @hide */
   1266     public static final int MIRACAST_SINK     = 2;
   1267     /** Internal use only @hide */
   1268     public void setMiracastMode(int mode) {
   1269         try {
   1270             mService.setMiracastMode(mode);
   1271         } catch(RemoteException e) {
   1272            // ignore
   1273         }
   1274     }
   1275 
   1276     /**
   1277      * Get a reference to WifiP2pService handler. This is used to establish
   1278      * an AsyncChannel communication with WifiService
   1279      *
   1280      * @return Messenger pointing to the WifiP2pService handler
   1281      * @hide
   1282      */
   1283     public Messenger getMessenger() {
   1284         try {
   1285             return mService.getMessenger();
   1286         } catch (RemoteException e) {
   1287             return null;
   1288         }
   1289     }
   1290 
   1291 }
   1292