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
17package android.net.wifi.p2p;
18
19import android.annotation.SdkConstant;
20import android.annotation.SdkConstant.SdkConstantType;
21import android.content.Context;
22import android.net.ConnectivityManager;
23import android.net.IConnectivityManager;
24import android.net.wifi.WpsInfo;
25import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo;
26import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceResponse;
27import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
28import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
29import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
30import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo;
31import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceResponse;
32import android.os.Binder;
33import android.os.Bundle;
34import android.os.IBinder;
35import android.os.Handler;
36import android.os.Looper;
37import android.os.Message;
38import android.os.Messenger;
39import android.os.RemoteException;
40import android.os.ServiceManager;
41import android.os.WorkSource;
42import android.text.TextUtils;
43import android.util.Log;
44
45import com.android.internal.util.AsyncChannel;
46import com.android.internal.util.Protocol;
47
48import java.util.HashMap;
49import java.util.List;
50import 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 */
138public 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