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