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