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