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