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