• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.CallbackExecutor;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.RequiresPermission;
24 import android.annotation.SdkConstant;
25 import android.annotation.SdkConstant.SdkConstantType;
26 import android.annotation.SystemApi;
27 import android.annotation.SystemService;
28 import android.compat.annotation.UnsupportedAppUsage;
29 import android.content.Context;
30 import android.net.MacAddress;
31 import android.net.NetworkInfo;
32 import android.net.wifi.ScanResult;
33 import android.net.wifi.WifiManager;
34 import android.net.wifi.WpsInfo;
35 import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo;
36 import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceResponse;
37 import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
38 import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
39 import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
40 import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo;
41 import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceResponse;
42 import android.os.Binder;
43 import android.os.Build;
44 import android.os.Bundle;
45 import android.os.Handler;
46 import android.os.Looper;
47 import android.os.Message;
48 import android.os.Messenger;
49 import android.os.RemoteException;
50 import android.text.TextUtils;
51 import android.util.CloseGuard;
52 import android.util.Log;
53 import android.view.Display;
54 
55 import androidx.annotation.RequiresApi;
56 
57 import com.android.internal.util.AsyncChannel;
58 import com.android.internal.util.Protocol;
59 import com.android.modules.utils.build.SdkLevel;
60 
61 import java.lang.annotation.Retention;
62 import java.lang.annotation.RetentionPolicy;
63 import java.lang.ref.Reference;
64 import java.util.ArrayList;
65 import java.util.HashMap;
66 import java.util.List;
67 import java.util.Map;
68 import java.util.Objects;
69 import java.util.concurrent.Executor;
70 import java.util.function.Consumer;
71 
72 /**
73  * This class provides the API for managing Wi-Fi peer-to-peer connectivity. This lets an
74  * application discover available peers, setup connection to peers and query for the list of peers.
75  * When a p2p connection is formed over wifi, the device continues to maintain the uplink
76  * connection over mobile or any other available network for internet connectivity on the device.
77  *
78  * <p> The API is asynchronous and responses to requests from an application are on listener
79  * callbacks provided by the application. The application needs to do an initialization with
80  * {@link #initialize} before doing any p2p operation.
81  *
82  * <p> Most application calls need a {@link ActionListener} instance for receiving callbacks
83  * {@link ActionListener#onSuccess} or {@link ActionListener#onFailure}. Action callbacks
84  * indicate whether the initiation of the action was a success or a failure.
85  * Upon failure, the reason of failure can be one of {@link #ERROR}, {@link #P2P_UNSUPPORTED}
86  * or {@link #BUSY}.
87  *
88  * <p> An application can initiate discovery of peers with {@link #discoverPeers}. An initiated
89  * discovery request from an application stays active until the device starts connecting to a peer
90  * ,forms a p2p group or there is an explicit {@link #stopPeerDiscovery}.
91  * Applications can listen to {@link #WIFI_P2P_DISCOVERY_CHANGED_ACTION} to know if a peer-to-peer
92  * discovery is running or stopped. Additionally, {@link #WIFI_P2P_PEERS_CHANGED_ACTION} indicates
93  * if the peer list has changed.
94  *
95  * <p> When an application needs to fetch the current list of peers, it can request the list
96  * of peers with {@link #requestPeers}. When the peer list is available
97  * {@link PeerListListener#onPeersAvailable} is called with the device list.
98  *
99  * <p> An application can initiate a connection request to a peer through {@link #connect}. See
100  * {@link WifiP2pConfig} for details on setting up the configuration. For communication with legacy
101  * Wi-Fi devices that do not support p2p, an app can create a group using {@link #createGroup}
102  * which creates an access point whose details can be fetched with {@link #requestGroupInfo}.
103  *
104  * <p> After a successful group formation through {@link #createGroup} or through {@link #connect},
105  * use {@link #requestConnectionInfo} to fetch the connection details. The connection info
106  * {@link WifiP2pInfo} contains the address of the group owner
107  * {@link WifiP2pInfo#groupOwnerAddress} and a flag {@link WifiP2pInfo#isGroupOwner} to indicate
108  * if the current device is a p2p group owner. A p2p client can thus communicate with
109  * the p2p group owner through a socket connection. If the current device is the p2p group owner,
110  * {@link WifiP2pInfo#groupOwnerAddress} is anonymized unless the caller holds the
111  * {@code android.Manifest.permission#LOCAL_MAC_ADDRESS} permission.
112  *
113  * <p> With peer discovery using {@link  #discoverPeers}, an application discovers the neighboring
114  * peers, but has no good way to figure out which peer to establish a connection with. For example,
115  * if a game application is interested in finding all the neighboring peers that are also running
116  * the same game, it has no way to find out until after the connection is setup. Pre-association
117  * service discovery is meant to address this issue of filtering the peers based on the running
118  * services.
119  *
120  * <p>With pre-association service discovery, an application can advertise a service for a
121  * application on a peer device prior to a connection setup between the devices.
122  * Currently, DNS based service discovery (Bonjour) and Upnp are the higher layer protocols
123  * supported. Get Bonjour resources at dns-sd.org and Upnp resources at upnp.org
124  * As an example, a video application can discover a Upnp capable media renderer
125  * prior to setting up a Wi-fi p2p connection with the device.
126  *
127  * <p> An application can advertise a Upnp or a Bonjour service with a call to
128  * {@link #addLocalService}. After a local service is added,
129  * the framework automatically responds to a peer application discovering the service prior
130  * to establishing a p2p connection. A call to {@link #removeLocalService} removes a local
131  * service and {@link #clearLocalServices} can be used to clear all local services.
132  *
133  * <p> An application that is looking for peer devices that support certain services
134  * can do so with a call to  {@link #discoverServices}. Prior to initiating the discovery,
135  * application can add service discovery request with a call to {@link #addServiceRequest},
136  * remove a service discovery request with a call to {@link #removeServiceRequest} or clear
137  * all requests with a call to {@link #clearServiceRequests}. When no service requests remain,
138  * a previously running service discovery will stop.
139  *
140  * The application is notified of a result of service discovery request through listener callbacks
141  * set through {@link #setDnsSdResponseListeners} for Bonjour or
142  * {@link #setUpnpServiceResponseListener} for Upnp.
143  *
144  * <p class="note"><strong>Note:</strong>
145  * Registering an application handler with {@link #initialize} requires the permissions
146  * {@link android.Manifest.permission#ACCESS_WIFI_STATE} and
147  * {@link android.Manifest.permission#CHANGE_WIFI_STATE} to perform any further peer-to-peer
148  * operations.
149  *
150  * {@see WifiP2pConfig}
151  * {@see WifiP2pInfo}
152  * {@see WifiP2pGroup}
153  * {@see WifiP2pDevice}
154  * {@see WifiP2pDeviceList}
155  * {@see android.net.wifi.WpsInfo}
156  */
157 @SystemService(Context.WIFI_P2P_SERVICE)
158 public class WifiP2pManager {
159     private static final String TAG = "WifiP2pManager";
160 
161     /** @hide */
162     public static final long FEATURE_SET_VENDOR_ELEMENTS        = 1L << 0;
163     /** @hide */
164     public static final long FEATURE_FLEXIBLE_DISCOVERY         = 1L << 1;
165     /** @hide */
166     public static final long FEATURE_GROUP_CLIENT_REMOVAL       = 1L << 2;
167     /** @hide */
168     public static final long FEATURE_GROUP_OWNER_IPV6_LINK_LOCAL_ADDRESS_PROVIDED = 1L << 3;
169 
170     /**
171      * Extra for transporting a WifiP2pConfig
172      * @hide
173      */
174     public static final String EXTRA_PARAM_KEY_CONFIG =
175             "android.net.wifi.p2p.EXTRA_PARAM_KEY_CONFIG";
176     /**
177      * Extra for transporting a WifiP2pServiceInfo
178      * @hide
179      */
180     public static final String EXTRA_PARAM_KEY_SERVICE_INFO =
181             "android.net.wifi.p2p.EXTRA_PARAM_KEY_SERVICE_INFO";
182     /**
183      * Extra for transporting a peer discovery frequency.
184      * @hide
185      */
186     public static final String EXTRA_PARAM_KEY_PEER_DISCOVERY_FREQ =
187             "android.net.wifi.p2p.EXTRA_PARAM_KEY_PEER_DISCOVERY_FREQ";
188     /**
189      * Extra for transporting a peer MAC address.
190      * @hide
191      */
192     public static final String EXTRA_PARAM_KEY_PEER_ADDRESS =
193             "android.net.wifi.p2p.EXTRA_PARAM_KEY_PEER_ADDRESS";
194     /**
195      * Extra used to indicate that a message is sent from Wifi internally
196      * @hide
197      */
198     public static final String EXTRA_PARAM_KEY_INTERNAL_MESSAGE =
199             "android.net.wifi.p2p.EXTRA_PARAM_KEY_INTERNAL_MESSAGE";
200 
201     /**
202      * Used to communicate the Display ID for multi display devices.
203      * @hide
204      **/
205     public static final String EXTRA_PARAM_KEY_DISPLAY_ID =
206             "android.net.wifi.p2p.EXTRA_PARAM_KEY_DISPLAY_ID";
207 
208     /**
209      * Extra for transporting a WifiP2pDevice.
210      * @hide
211      */
212     public static final String EXTRA_PARAM_KEY_DEVICE =
213             "android.net.wifi.p2p.EXTRA_PARAM_KEY_DEVICE";
214     /**
215      * Extra for transporting a WPS PIN.
216      * @hide
217      */
218     public static final String EXTRA_PARAM_KEY_WPS_PIN =
219             "android.net.wifi.p2p.EXTRA_PARAM_KEY_WPS_PIN";
220 
221     /**
222      * Extra for transporting vendor-specific information element list
223      * @hide
224      */
225     public static final String EXTRA_PARAM_KEY_INFORMATION_ELEMENT_LIST =
226             "android.net.wifi.p2p.EXTRA_PARAM_KEY_INFORMATION_ELEMENT_LIST";
227 
228     /**
229      * Key for transporting a bundle of extra information.
230      * @hide
231      */
232     public static final String EXTRA_PARAM_KEY_BUNDLE =
233             "android.net.wifi.p2p.EXTRA_PARAM_KEY_BUNDLE";
234 
235     /**
236      * Broadcast intent action to indicate whether Wi-Fi p2p is enabled or disabled. An
237      * extra {@link #EXTRA_WIFI_STATE} provides the state information as int.
238      *
239      * @see #EXTRA_WIFI_STATE
240      */
241     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
242     public static final String WIFI_P2P_STATE_CHANGED_ACTION =
243         "android.net.wifi.p2p.STATE_CHANGED";
244 
245     /**
246      * The lookup key for an int that indicates whether Wi-Fi p2p is enabled or disabled.
247      * Retrieve it with {@link android.content.Intent#getIntExtra(String,int)}.
248      *
249      * @see #WIFI_P2P_STATE_DISABLED
250      * @see #WIFI_P2P_STATE_ENABLED
251      */
252     public static final String EXTRA_WIFI_STATE = "wifi_p2p_state";
253 
254     /** @hide */
255     @IntDef({
256             WIFI_P2P_STATE_DISABLED,
257             WIFI_P2P_STATE_ENABLED})
258     @Retention(RetentionPolicy.SOURCE)
259     public @interface WifiP2pState {
260     }
261 
262     /**
263      * Wi-Fi p2p is disabled.
264      *
265      * @see #WIFI_P2P_STATE_CHANGED_ACTION
266      */
267     public static final int WIFI_P2P_STATE_DISABLED = 1;
268 
269     /**
270      * Wi-Fi p2p is enabled.
271      *
272      * @see #WIFI_P2P_STATE_CHANGED_ACTION
273      */
274     public static final int WIFI_P2P_STATE_ENABLED = 2;
275 
276     /**
277      * Broadcast intent action indicating that the state of Wi-Fi p2p connectivity
278      * has changed. One extra {@link #EXTRA_WIFI_P2P_INFO} provides the p2p connection info in
279      * the form of a {@link WifiP2pInfo} object. Another extra {@link #EXTRA_NETWORK_INFO} provides
280      * the network info in the form of a {@link android.net.NetworkInfo}. A third extra provides
281      * the details of the group and may contain a {@code null}.
282      *
283      * All of these permissions are required to receive this broadcast:
284      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} and either
285      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
286      * {@link android.Manifest.permission#NEARBY_WIFI_DEVICES}
287      *
288      * @see #EXTRA_WIFI_P2P_INFO
289      * @see #EXTRA_NETWORK_INFO
290      * @see #EXTRA_WIFI_P2P_GROUP
291      */
292     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
293     public static final String WIFI_P2P_CONNECTION_CHANGED_ACTION =
294         "android.net.wifi.p2p.CONNECTION_STATE_CHANGE";
295 
296     /**
297      * The lookup key for a {@link android.net.wifi.p2p.WifiP2pInfo} object
298      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
299      */
300     public static final String EXTRA_WIFI_P2P_INFO = "wifiP2pInfo";
301 
302     /**
303      * The lookup key for a {@link android.net.NetworkInfo} object associated with the
304      * p2p network. Retrieve with
305      * {@link android.content.Intent#getParcelableExtra(String)}.
306      */
307     public static final String EXTRA_NETWORK_INFO = "networkInfo";
308 
309     /**
310      * The lookup key for a {@link android.net.wifi.p2p.WifiP2pGroup} object
311      * associated with the p2p network. Retrieve with
312      * {@link android.content.Intent#getParcelableExtra(String)}.
313      */
314     public static final String EXTRA_WIFI_P2P_GROUP = "p2pGroupInfo";
315 
316     /**
317      * Broadcast intent action indicating that the available peer list has changed. This
318      * can be sent as a result of peers being found, lost or updated.
319      *
320      * All of these permissions are required to receive this broadcast:
321      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} and either
322      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
323      * {@link android.Manifest.permission#NEARBY_WIFI_DEVICES}
324      *
325      * <p> An extra {@link #EXTRA_P2P_DEVICE_LIST} provides the full list of
326      * current peers. The full list of peers can also be obtained any time with
327      * {@link #requestPeers}.
328      *
329      * @see #EXTRA_P2P_DEVICE_LIST
330      */
331     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
332     public static final String WIFI_P2P_PEERS_CHANGED_ACTION =
333         "android.net.wifi.p2p.PEERS_CHANGED";
334 
335      /**
336       * The lookup key for a {@link android.net.wifi.p2p.WifiP2pDeviceList} object representing
337       * the new peer list when {@link #WIFI_P2P_PEERS_CHANGED_ACTION} broadcast is sent.
338       *
339       * <p>Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
340       */
341     public static final String EXTRA_P2P_DEVICE_LIST = "wifiP2pDeviceList";
342 
343     /**
344      * Broadcast intent action indicating that peer discovery has either started or stopped.
345      * One extra {@link #EXTRA_DISCOVERY_STATE} indicates whether discovery has started
346      * or stopped.
347      *
348      * <p>Note that discovery will be stopped during a connection setup. If the application tries
349      * to re-initiate discovery during this time, it can fail.
350      */
351     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
352     public static final String WIFI_P2P_DISCOVERY_CHANGED_ACTION =
353         "android.net.wifi.p2p.DISCOVERY_STATE_CHANGE";
354 
355     /**
356      * The lookup key for an int that indicates whether p2p discovery has started or stopped.
357      * Retrieve it with {@link android.content.Intent#getIntExtra(String,int)}.
358      *
359      * @see #WIFI_P2P_DISCOVERY_STARTED
360      * @see #WIFI_P2P_DISCOVERY_STOPPED
361      */
362     public static final String EXTRA_DISCOVERY_STATE = "discoveryState";
363 
364     /** @hide */
365     @IntDef({
366             WIFI_P2P_DISCOVERY_STOPPED,
367             WIFI_P2P_DISCOVERY_STARTED})
368     @Retention(RetentionPolicy.SOURCE)
369     public @interface WifiP2pDiscoveryState {
370     }
371 
372     /**
373      * p2p discovery has stopped
374      *
375      * @see #WIFI_P2P_DISCOVERY_CHANGED_ACTION
376      */
377     public static final int WIFI_P2P_DISCOVERY_STOPPED = 1;
378 
379     /**
380      * p2p discovery has started
381      *
382      * @see #WIFI_P2P_DISCOVERY_CHANGED_ACTION
383      */
384     public static final int WIFI_P2P_DISCOVERY_STARTED = 2;
385 
386     /**
387      * Broadcast intent action indicating that peer listen has either started or stopped.
388      * One extra {@link #EXTRA_LISTEN_STATE} indicates whether listen has started or stopped.
389      */
390     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
391     public static final String ACTION_WIFI_P2P_LISTEN_STATE_CHANGED =
392             "android.net.wifi.p2p.action.WIFI_P2P_LISTEN_STATE_CHANGED";
393 
394     /**
395      * The lookup key for an int that indicates whether p2p listen has started or stopped.
396      * Retrieve it with {@link android.content.Intent#getIntExtra(String,int)}.
397      *
398      * @see #WIFI_P2P_LISTEN_STARTED
399      * @see #WIFI_P2P_LISTEN_STOPPED
400      */
401     public static final String EXTRA_LISTEN_STATE = "android.net.wifi.p2p.extra.LISTEN_STATE";
402 
403     /** @hide */
404     @IntDef({
405             WIFI_P2P_LISTEN_STOPPED,
406             WIFI_P2P_LISTEN_STARTED})
407     @Retention(RetentionPolicy.SOURCE)
408     public @interface WifiP2pListenState {
409     }
410 
411     /**
412      * p2p listen has stopped
413      *
414      * @see #ACTION_WIFI_P2P_LISTEN_STATE_CHANGED
415      */
416     public static final int WIFI_P2P_LISTEN_STOPPED = 1;
417 
418     /**
419      * p2p listen has started
420      *
421      * @see #ACTION_WIFI_P2P_LISTEN_STATE_CHANGED
422      */
423     public static final int WIFI_P2P_LISTEN_STARTED = 2;
424 
425     /**
426      * Broadcast intent action indicating that this device details have changed.
427      *
428      * <p> An extra {@link #EXTRA_WIFI_P2P_DEVICE} provides this device details.
429      * The valid device details can also be obtained with
430      * {@link #requestDeviceInfo(Channel, DeviceInfoListener)} when p2p is enabled.
431      * To get information notifications on P2P getting enabled refers
432      * {@link #WIFI_P2P_STATE_ENABLED}.
433      *
434      * <p> The {@link #EXTRA_WIFI_P2P_DEVICE} extra contains an anonymized version of the device's
435      * MAC address. Callers holding the {@code android.Manifest.permission#LOCAL_MAC_ADDRESS}
436      * permission can use {@link #requestDeviceInfo} to obtain the actual MAC address of this
437      * device.
438      *
439      * All of these permissions are required to receive this broadcast:
440      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} and either
441      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
442      * {@link android.Manifest.permission#NEARBY_WIFI_DEVICES}
443      *
444      * @see #EXTRA_WIFI_P2P_DEVICE
445      */
446     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
447     public static final String WIFI_P2P_THIS_DEVICE_CHANGED_ACTION =
448         "android.net.wifi.p2p.THIS_DEVICE_CHANGED";
449 
450     /**
451      * The lookup key for a {@link android.net.wifi.p2p.WifiP2pDevice} object
452      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
453      */
454     public static final String EXTRA_WIFI_P2P_DEVICE = "wifiP2pDevice";
455 
456     /**
457      * Broadcast intent action indicating that remembered persistent groups have changed.
458      *
459      * You can <em>not</em> receive this through components declared
460      * in manifests, only by explicitly registering for it with
461      * {@link android.content.Context#registerReceiver(android.content.BroadcastReceiver,
462      * android.content.IntentFilter) Context.registerReceiver()}.
463      *
464      * @hide
465      */
466     @SystemApi
467     public static final String ACTION_WIFI_P2P_PERSISTENT_GROUPS_CHANGED =
468             "android.net.wifi.p2p.action.WIFI_P2P_PERSISTENT_GROUPS_CHANGED";
469 
470     /**
471      * Broadcast intent action indicating whether or not current connecting
472      * request is accepted.
473      *
474      * The connecting request is initiated by
475      * {@link #connect(Channel, WifiP2pConfig, ActionListener)}.
476      * <p>The {@link #EXTRA_REQUEST_RESPONSE} extra indicates whether or not current
477      * request is accepted or rejected.
478      * <p>The {@link #EXTRA_REQUEST_CONFIG} extra indicates the responsed configuration.
479      */
480     public static final String ACTION_WIFI_P2P_REQUEST_RESPONSE_CHANGED =
481             "android.net.wifi.p2p.action.WIFI_P2P_REQUEST_RESPONSE_CHANGED";
482 
483     /**
484      * The lookup key for the result of a request, true if accepted, false otherwise.
485      */
486     public static final String EXTRA_REQUEST_RESPONSE =
487             "android.net.wifi.p2p.extra.REQUEST_RESPONSE";
488 
489     /**
490      * The lookup key for the {@link WifiP2pConfig} object of a request.
491      */
492     public static final String EXTRA_REQUEST_CONFIG =
493             "android.net.wifi.p2p.extra.REQUEST_CONFIG";
494 
495     /**
496      * The lookup key for a handover message returned by the WifiP2pService.
497      * @hide
498      */
499     public static final String EXTRA_HANDOVER_MESSAGE =
500             "android.net.wifi.p2p.EXTRA_HANDOVER_MESSAGE";
501 
502     /**
503      * The lookup key for a calling package name from WifiP2pManager
504      * @hide
505      */
506     public static final String CALLING_PACKAGE =
507             "android.net.wifi.p2p.CALLING_PACKAGE";
508 
509     /**
510      * The lookup key for a calling feature id from WifiP2pManager
511      * @hide
512      */
513     public static final String CALLING_FEATURE_ID =
514             "android.net.wifi.p2p.CALLING_FEATURE_ID";
515 
516     /**
517      * The lookup key for a calling package binder from WifiP2pManager
518      * @hide
519      */
520     public static final String CALLING_BINDER =
521             "android.net.wifi.p2p.CALLING_BINDER";
522 
523     /**
524      * Run P2P scan on all channels.
525      * @hide
526      */
527     public static final int WIFI_P2P_SCAN_FULL = 0;
528 
529     /**
530      * Run P2P scan only on social channels.
531      * @hide
532      */
533     public static final int WIFI_P2P_SCAN_SOCIAL = 1;
534 
535     /**
536      * Run P2P scan only on a specific channel.
537      * @hide
538      */
539     public static final int WIFI_P2P_SCAN_SINGLE_FREQ = 2;
540 
541     /** @hide */
542     @IntDef(prefix = {"WIFI_P2P_SCAN_"}, value = {
543             WIFI_P2P_SCAN_FULL,
544             WIFI_P2P_SCAN_SOCIAL,
545             WIFI_P2P_SCAN_SINGLE_FREQ})
546     @Retention(RetentionPolicy.SOURCE)
547     public @interface WifiP2pScanType {
548     }
549 
550     /**
551      * No channel specified for discover Peers APIs. Let lower layer decide the frequencies to scan
552      * based on the WifiP2pScanType.
553      * @hide
554      */
555     public static final int WIFI_P2P_SCAN_FREQ_UNSPECIFIED = 0;
556 
557     /**
558      * Maximum length in bytes of all vendor specific information elements (IEs) allowed to
559      * set during Wi-Fi Direct (P2P) discovery.
560      */
561     private static final int WIFI_P2P_VENDOR_ELEMENTS_MAXIMUM_LENGTH = 512;
562 
563     IWifiP2pManager mService;
564 
565     private static final int BASE = Protocol.BASE_WIFI_P2P_MANAGER;
566 
567     /** @hide */
568     public static final int DISCOVER_PEERS                          = BASE + 1;
569     /** @hide */
570     public static final int DISCOVER_PEERS_FAILED                   = BASE + 2;
571     /** @hide */
572     public static final int DISCOVER_PEERS_SUCCEEDED                = BASE + 3;
573 
574     /** @hide */
575     public static final int STOP_DISCOVERY                          = BASE + 4;
576     /** @hide */
577     public static final int STOP_DISCOVERY_FAILED                   = BASE + 5;
578     /** @hide */
579     public static final int STOP_DISCOVERY_SUCCEEDED                = BASE + 6;
580 
581     /** @hide */
582     public static final int CONNECT                                 = BASE + 7;
583     /** @hide */
584     public static final int CONNECT_FAILED                          = BASE + 8;
585     /** @hide */
586     public static final int CONNECT_SUCCEEDED                       = BASE + 9;
587 
588     /** @hide */
589     public static final int CANCEL_CONNECT                          = BASE + 10;
590     /** @hide */
591     public static final int CANCEL_CONNECT_FAILED                   = BASE + 11;
592     /** @hide */
593     public static final int CANCEL_CONNECT_SUCCEEDED                = BASE + 12;
594 
595     /** @hide */
596     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
597     public static final int CREATE_GROUP                            = BASE + 13;
598     /** @hide */
599     public static final int CREATE_GROUP_FAILED                     = BASE + 14;
600     /** @hide */
601     public static final int CREATE_GROUP_SUCCEEDED                  = BASE + 15;
602 
603     /** @hide */
604     public static final int REMOVE_GROUP                            = BASE + 16;
605     /** @hide */
606     public static final int REMOVE_GROUP_FAILED                     = BASE + 17;
607     /** @hide */
608     public static final int REMOVE_GROUP_SUCCEEDED                  = BASE + 18;
609 
610     /** @hide */
611     public static final int REQUEST_PEERS                           = BASE + 19;
612     /** @hide */
613     public static final int RESPONSE_PEERS                          = BASE + 20;
614 
615     /** @hide */
616     public static final int REQUEST_CONNECTION_INFO                 = BASE + 21;
617     /** @hide */
618     public static final int RESPONSE_CONNECTION_INFO                = BASE + 22;
619 
620     /** @hide */
621     public static final int REQUEST_GROUP_INFO                      = BASE + 23;
622     /** @hide */
623     public static final int RESPONSE_GROUP_INFO                     = BASE + 24;
624 
625     /** @hide */
626     public static final int ADD_LOCAL_SERVICE                       = BASE + 28;
627     /** @hide */
628     public static final int ADD_LOCAL_SERVICE_FAILED                = BASE + 29;
629     /** @hide */
630     public static final int ADD_LOCAL_SERVICE_SUCCEEDED             = BASE + 30;
631 
632     /** @hide */
633     public static final int REMOVE_LOCAL_SERVICE                    = BASE + 31;
634     /** @hide */
635     public static final int REMOVE_LOCAL_SERVICE_FAILED             = BASE + 32;
636     /** @hide */
637     public static final int REMOVE_LOCAL_SERVICE_SUCCEEDED          = BASE + 33;
638 
639     /** @hide */
640     public static final int CLEAR_LOCAL_SERVICES                    = BASE + 34;
641     /** @hide */
642     public static final int CLEAR_LOCAL_SERVICES_FAILED             = BASE + 35;
643     /** @hide */
644     public static final int CLEAR_LOCAL_SERVICES_SUCCEEDED          = BASE + 36;
645 
646     /** @hide */
647     public static final int ADD_SERVICE_REQUEST                     = BASE + 37;
648     /** @hide */
649     public static final int ADD_SERVICE_REQUEST_FAILED              = BASE + 38;
650     /** @hide */
651     public static final int ADD_SERVICE_REQUEST_SUCCEEDED           = BASE + 39;
652 
653     /** @hide */
654     public static final int REMOVE_SERVICE_REQUEST                  = BASE + 40;
655     /** @hide */
656     public static final int REMOVE_SERVICE_REQUEST_FAILED           = BASE + 41;
657     /** @hide */
658     public static final int REMOVE_SERVICE_REQUEST_SUCCEEDED        = BASE + 42;
659 
660     /** @hide */
661     public static final int CLEAR_SERVICE_REQUESTS                  = BASE + 43;
662     /** @hide */
663     public static final int CLEAR_SERVICE_REQUESTS_FAILED           = BASE + 44;
664     /** @hide */
665     public static final int CLEAR_SERVICE_REQUESTS_SUCCEEDED        = BASE + 45;
666 
667     /** @hide */
668     public static final int DISCOVER_SERVICES                       = BASE + 46;
669     /** @hide */
670     public static final int DISCOVER_SERVICES_FAILED                = BASE + 47;
671     /** @hide */
672     public static final int DISCOVER_SERVICES_SUCCEEDED             = BASE + 48;
673 
674     /** @hide */
675     public static final int PING                                    = BASE + 49;
676 
677     /** @hide */
678     public static final int RESPONSE_SERVICE                        = BASE + 50;
679 
680     /** @hide */
681     public static final int SET_DEVICE_NAME                         = BASE + 51;
682     /** @hide */
683     public static final int SET_DEVICE_NAME_FAILED                  = BASE + 52;
684     /** @hide */
685     public static final int SET_DEVICE_NAME_SUCCEEDED               = BASE + 53;
686 
687     /** @hide */
688     public static final int DELETE_PERSISTENT_GROUP                 = BASE + 54;
689     /** @hide */
690     public static final int DELETE_PERSISTENT_GROUP_FAILED          = BASE + 55;
691     /** @hide */
692     public static final int DELETE_PERSISTENT_GROUP_SUCCEEDED       = BASE + 56;
693 
694     /** @hide */
695     public static final int REQUEST_PERSISTENT_GROUP_INFO           = BASE + 57;
696     /** @hide */
697     public static final int RESPONSE_PERSISTENT_GROUP_INFO          = BASE + 58;
698 
699     /** @hide */
700     public static final int SET_WFD_INFO                            = BASE + 59;
701     /** @hide */
702     public static final int SET_WFD_INFO_FAILED                     = BASE + 60;
703     /** @hide */
704     public static final int SET_WFD_INFO_SUCCEEDED                  = BASE + 61;
705 
706     /** @hide */
707     public static final int START_WPS                               = BASE + 62;
708     /** @hide */
709     public static final int START_WPS_FAILED                        = BASE + 63;
710     /** @hide */
711     public static final int START_WPS_SUCCEEDED                     = BASE + 64;
712 
713     /** @hide */
714     public static final int START_LISTEN                            = BASE + 65;
715     /** @hide */
716     public static final int START_LISTEN_FAILED                     = BASE + 66;
717     /** @hide */
718     public static final int START_LISTEN_SUCCEEDED                  = BASE + 67;
719 
720     /** @hide */
721     public static final int STOP_LISTEN                             = BASE + 68;
722     /** @hide */
723     public static final int STOP_LISTEN_FAILED                      = BASE + 69;
724     /** @hide */
725     public static final int STOP_LISTEN_SUCCEEDED                   = BASE + 70;
726 
727     /** @hide */
728     public static final int SET_CHANNEL                             = BASE + 71;
729     /** @hide */
730     public static final int SET_CHANNEL_FAILED                      = BASE + 72;
731     /** @hide */
732     public static final int SET_CHANNEL_SUCCEEDED                   = BASE + 73;
733 
734     /** @hide */
735     public static final int GET_HANDOVER_REQUEST                    = BASE + 75;
736     /** @hide */
737     public static final int GET_HANDOVER_SELECT                     = BASE + 76;
738     /** @hide */
739     public static final int RESPONSE_GET_HANDOVER_MESSAGE           = BASE + 77;
740     /** @hide */
741     public static final int INITIATOR_REPORT_NFC_HANDOVER           = BASE + 78;
742     /** @hide */
743     public static final int RESPONDER_REPORT_NFC_HANDOVER           = BASE + 79;
744     /** @hide */
745     public static final int REPORT_NFC_HANDOVER_SUCCEEDED           = BASE + 80;
746     /** @hide */
747     public static final int REPORT_NFC_HANDOVER_FAILED              = BASE + 81;
748 
749     /** @hide */
750     public static final int FACTORY_RESET                           = BASE + 82;
751     /** @hide */
752     public static final int FACTORY_RESET_FAILED                    = BASE + 83;
753     /** @hide */
754     public static final int FACTORY_RESET_SUCCEEDED                 = BASE + 84;
755 
756     /** @hide */
757     public static final int REQUEST_ONGOING_PEER_CONFIG             = BASE + 85;
758     /** @hide */
759     public static final int RESPONSE_ONGOING_PEER_CONFIG            = BASE + 86;
760     /** @hide */
761     public static final int SET_ONGOING_PEER_CONFIG                 = BASE + 87;
762     /** @hide */
763     public static final int SET_ONGOING_PEER_CONFIG_FAILED          = BASE + 88;
764     /** @hide */
765     public static final int SET_ONGOING_PEER_CONFIG_SUCCEEDED       = BASE + 89;
766 
767     /** @hide */
768     public static final int REQUEST_P2P_STATE                       = BASE + 90;
769     /** @hide */
770     public static final int RESPONSE_P2P_STATE                      = BASE + 91;
771 
772     /** @hide */
773     public static final int REQUEST_DISCOVERY_STATE                 = BASE + 92;
774     /** @hide */
775     public static final int RESPONSE_DISCOVERY_STATE                = BASE + 93;
776 
777     /** @hide */
778     public static final int REQUEST_NETWORK_INFO                    = BASE + 94;
779     /** @hide */
780     public static final int RESPONSE_NETWORK_INFO                   = BASE + 95;
781 
782     /** @hide */
783     public static final int UPDATE_CHANNEL_INFO                     = BASE + 96;
784 
785     /** @hide */
786     public static final int REQUEST_DEVICE_INFO                     = BASE + 97;
787     /** @hide */
788     public static final int RESPONSE_DEVICE_INFO                    = BASE + 98;
789 
790     /** @hide */
791     public static final int REMOVE_CLIENT                           = BASE + 99;
792     /** @hide */
793     public static final int REMOVE_CLIENT_FAILED                    = BASE + 100;
794     /** @hide */
795     public static final int REMOVE_CLIENT_SUCCEEDED                 = BASE + 101;
796 
797     /** @hide */
798     public static final int ADD_EXTERNAL_APPROVER                   = BASE + 102;
799     /** @hide */
800     public static final int EXTERNAL_APPROVER_ATTACH                = BASE + 103;
801     /** @hide */
802     public static final int EXTERNAL_APPROVER_DETACH                = BASE + 104;
803     /** @hide */
804     public static final int EXTERNAL_APPROVER_CONNECTION_REQUESTED  = BASE + 105;
805     /** @hide */
806     public static final int EXTERNAL_APPROVER_PIN_GENERATED         = BASE + 106;
807 
808     /** @hide */
809     public static final int REMOVE_EXTERNAL_APPROVER                = BASE + 107;
810     /** @hide */
811     public static final int REMOVE_EXTERNAL_APPROVER_FAILED         = BASE + 108;
812     /** @hide */
813     public static final int REMOVE_EXTERNAL_APPROVER_SUCCEEDED      = BASE + 109;
814 
815     /** @hide */
816     public static final int SET_CONNECTION_REQUEST_RESULT           = BASE + 110;
817     /** @hide */
818     public static final int SET_CONNECTION_REQUEST_RESULT_FAILED    = BASE + 111;
819     /** @hide */
820     public static final int SET_CONNECTION_REQUEST_RESULT_SUCCEEDED = BASE + 112;
821 
822     /** @hide */
823     public static final int SET_VENDOR_ELEMENTS                       = BASE + 113;
824     /** @hide */
825     public static final int SET_VENDOR_ELEMENTS_FAILED                = BASE + 114;
826     /** @hide */
827     public static final int SET_VENDOR_ELEMENTS_SUCCEEDED             = BASE + 115;
828 
829     /** @hide */
830     public static final int GET_LISTEN_STATE                          = BASE + 116;
831     /** @hide */
832     public static final int GET_LISTEN_STATE_FAILED                   = BASE + 117;
833     /** @hide */
834     public static final int RESPONSE_GET_LISTEN_STATE                 = BASE + 118;
835 
836     /**
837      * Create a new WifiP2pManager instance. Applications use
838      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
839      * the standard {@link android.content.Context#WIFI_P2P_SERVICE Context.WIFI_P2P_SERVICE}.
840      * @param service the Binder interface
841      * @hide - hide this because it takes in a parameter of type IWifiP2pManager, which
842      * is a system private class.
843      */
844     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
WifiP2pManager(IWifiP2pManager service)845     public WifiP2pManager(IWifiP2pManager service) {
846         mService = service;
847     }
848 
849     /**
850      * Passed with {@link ActionListener#onFailure}.
851      * Indicates that the operation failed due to an internal error.
852      */
853     public static final int ERROR               = 0;
854 
855     /**
856      * Passed with {@link ActionListener#onFailure}.
857      * Indicates that the operation failed because p2p is unsupported on the device.
858      */
859     public static final int P2P_UNSUPPORTED     = 1;
860 
861     /**
862      * Passed with {@link ActionListener#onFailure}.
863      * Indicates that the operation failed because the framework is busy and
864      * unable to service the request
865      */
866     public static final int BUSY                = 2;
867 
868     /**
869      * Passed with {@link ActionListener#onFailure}.
870      * Indicates that the {@link #discoverServices} failed because no service
871      * requests are added. Use {@link #addServiceRequest} to add a service
872      * request.
873      */
874     public static final int NO_SERVICE_REQUESTS = 3;
875 
876     /** Interface for callback invocation when framework channel is lost */
877     public interface ChannelListener {
878         /**
879          * The channel to the framework has been disconnected.
880          * Application could try re-initializing using {@link #initialize}
881          */
onChannelDisconnected()882         public void onChannelDisconnected();
883     }
884 
885     /** Interface for callback invocation on an application action */
886     public interface ActionListener {
887         /** The operation succeeded */
onSuccess()888         public void onSuccess();
889         /**
890          * The operation failed
891          * @param reason The reason for failure could be one of {@link #P2P_UNSUPPORTED},
892          * {@link #ERROR} or {@link #BUSY}
893          */
onFailure(int reason)894         public void onFailure(int reason);
895     }
896 
897     /** Interface for callback invocation when peer list is available */
898     public interface PeerListListener {
899         /**
900          * The requested peer list is available
901          * @param peers List of available peers
902          */
onPeersAvailable(WifiP2pDeviceList peers)903         public void onPeersAvailable(WifiP2pDeviceList peers);
904     }
905 
906     /** Interface for callback invocation when connection info is available */
907     public interface ConnectionInfoListener {
908         /**
909          * The requested connection info is available
910          * @param info Wi-Fi p2p connection info
911          */
onConnectionInfoAvailable(WifiP2pInfo info)912         public void onConnectionInfoAvailable(WifiP2pInfo info);
913     }
914 
915     /** Interface for callback invocation when group info is available */
916     public interface GroupInfoListener {
917         /**
918          * The requested p2p group info is available
919          * @param group Wi-Fi p2p group info
920          */
onGroupInfoAvailable(WifiP2pGroup group)921         public void onGroupInfoAvailable(WifiP2pGroup group);
922     }
923 
924    /**
925     * Interface for callback invocation when service discovery response other than
926     * Upnp or Bonjour is received
927     */
928     public interface ServiceResponseListener {
929 
930         /**
931          * The requested service response is available.
932          *
933          * @param protocolType protocol type. currently only
934          * {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}.
935          * @param responseData service discovery response data based on the requested
936          *  service protocol type. The format depends on the service type.
937          * @param srcDevice source device.
938          */
onServiceAvailable(int protocolType, byte[] responseData, WifiP2pDevice srcDevice)939         public void onServiceAvailable(int protocolType,
940                 byte[] responseData, WifiP2pDevice srcDevice);
941     }
942 
943     /**
944      * Interface for callback invocation when Bonjour service discovery response
945      * is received
946      */
947     public interface DnsSdServiceResponseListener {
948 
949         /**
950          * The requested Bonjour service response is available.
951          *
952          * <p>This function is invoked when the device with the specified Bonjour
953          * registration type returned the instance name.
954          * @param instanceName instance name.<br>
955          *  e.g) "MyPrinter".
956          * @param registrationType <br>
957          * e.g) "_ipp._tcp.local."
958          * @param srcDevice source device.
959          */
onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice srcDevice)960         public void onDnsSdServiceAvailable(String instanceName,
961                 String registrationType, WifiP2pDevice srcDevice);
962 
963    }
964 
965     /**
966      * Interface for callback invocation when Bonjour TXT record is available
967      * for a service
968      */
969    public interface DnsSdTxtRecordListener {
970         /**
971          * The requested Bonjour service response is available.
972          *
973          * <p>This function is invoked when the device with the specified full
974          * service domain service returned TXT record.
975          *
976          * @param fullDomainName full domain name. <br>
977          * e.g) "MyPrinter._ipp._tcp.local.".
978          * @param txtRecordMap TXT record data as a map of key/value pairs
979          * @param srcDevice source device.
980          */
onDnsSdTxtRecordAvailable(String fullDomainName, Map<String, String> txtRecordMap, WifiP2pDevice srcDevice)981         public void onDnsSdTxtRecordAvailable(String fullDomainName,
982                 Map<String, String> txtRecordMap,
983                 WifiP2pDevice srcDevice);
984    }
985 
986     /**
987      * Interface for callback invocation when upnp service discovery response
988      * is received
989      * */
990     public interface UpnpServiceResponseListener {
991 
992         /**
993          * The requested upnp service response is available.
994          *
995          * <p>This function is invoked when the specified device or service is found.
996          *
997          * @param uniqueServiceNames The list of unique service names.<br>
998          * e.g) uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp-org:device:
999          * MediaServer:1
1000          * @param srcDevice source device.
1001          */
onUpnpServiceAvailable(List<String> uniqueServiceNames, WifiP2pDevice srcDevice)1002         public void onUpnpServiceAvailable(List<String> uniqueServiceNames,
1003                 WifiP2pDevice srcDevice);
1004     }
1005 
1006 
1007     /**
1008      * Interface for callback invocation when stored group info list is available
1009      *
1010      * @hide
1011      */
1012     @SystemApi
1013     public interface PersistentGroupInfoListener {
1014         /**
1015          * The requested stored p2p group info list is available
1016          * @param groups Wi-Fi p2p group info list
1017          */
onPersistentGroupInfoAvailable(@onNull WifiP2pGroupList groups)1018         void onPersistentGroupInfoAvailable(@NonNull WifiP2pGroupList groups);
1019     }
1020 
1021     /**
1022      * Interface for callback invocation when Handover Request or Select Message is available
1023      * @hide
1024      */
1025     public interface HandoverMessageListener {
onHandoverMessageAvailable(String handoverMessage)1026         public void onHandoverMessageAvailable(String handoverMessage);
1027     }
1028 
1029     /** Interface for callback invocation when p2p state is available
1030      *  in response to {@link #requestP2pState}.
1031      */
1032     public interface P2pStateListener {
1033         /**
1034          * The requested p2p state is available.
1035          * @param state Wi-Fi p2p state
1036          *        @see #WIFI_P2P_STATE_DISABLED
1037          *        @see #WIFI_P2P_STATE_ENABLED
1038          */
onP2pStateAvailable(@ifiP2pState int state)1039         void onP2pStateAvailable(@WifiP2pState int state);
1040     }
1041 
1042     /** Interface for callback invocation when p2p state is available
1043      *  in response to {@link #requestDiscoveryState}.
1044      */
1045     public interface DiscoveryStateListener {
1046         /**
1047          * The requested p2p discovery state is available.
1048          * @param state Wi-Fi p2p discovery state
1049          *        @see #WIFI_P2P_DISCOVERY_STARTED
1050          *        @see #WIFI_P2P_DISCOVERY_STOPPED
1051          */
onDiscoveryStateAvailable(@ifiP2pDiscoveryState int state)1052         void onDiscoveryStateAvailable(@WifiP2pDiscoveryState int state);
1053     }
1054 
1055     /** Interface for callback invocation when p2p state is available
1056      *  in response to {@link #getListenState}.
1057      *  @hide
1058      */
1059     public interface ListenStateListener {
1060         /**
1061          * The requested p2p listen state is available.
1062          * @param state Wi-Fi p2p listen state
1063          *        @see #WIFI_P2P_LISTEN_STARTED
1064          *        @see #WIFI_P2P_LISTEN_STOPPED
1065          */
onListenStateAvailable(@ifiP2pListenState int state)1066         void onListenStateAvailable(@WifiP2pListenState int state);
1067     }
1068 
1069     /** Interface for callback invocation when {@link android.net.NetworkInfo} is available
1070      *  in response to {@link #requestNetworkInfo}.
1071      */
1072     public interface NetworkInfoListener {
1073         /**
1074          * The requested {@link android.net.NetworkInfo} is available
1075          * @param networkInfo Wi-Fi p2p {@link android.net.NetworkInfo}
1076          */
onNetworkInfoAvailable(@onNull NetworkInfo networkInfo)1077         void onNetworkInfoAvailable(@NonNull NetworkInfo networkInfo);
1078     }
1079 
1080     /**
1081      * Interface for callback invocation when ongoing peer info is available
1082      * @hide
1083      */
1084     public interface OngoingPeerInfoListener {
1085         /**
1086          * The requested ongoing WifiP2pConfig is available
1087          * @param peerConfig WifiP2pConfig for current connecting session
1088          */
onOngoingPeerAvailable(WifiP2pConfig peerConfig)1089         void onOngoingPeerAvailable(WifiP2pConfig peerConfig);
1090     }
1091 
1092     /** Interface for callback invocation when {@link android.net.wifi.p2p.WifiP2pDevice}
1093      *  is available in response to {@link #requestDeviceInfo(Channel, DeviceInfoListener)}.
1094      */
1095     public interface DeviceInfoListener {
1096         /**
1097          * The requested {@link android.net.wifi.p2p.WifiP2pDevice} is available.
1098          * @param wifiP2pDevice Wi-Fi p2p {@link android.net.wifi.p2p.WifiP2pDevice}
1099          */
onDeviceInfoAvailable(@ullable WifiP2pDevice wifiP2pDevice)1100         void onDeviceInfoAvailable(@Nullable WifiP2pDevice wifiP2pDevice);
1101     }
1102 
1103     /**
1104      * Interface for callback invocation when an incoming request is received.
1105      *
1106      * This callback is registered by
1107      * {@link #addExternalApprover(Channel, MacAddress, ExternalApproverRequestListener)}.
1108      */
1109     public interface ExternalApproverRequestListener {
1110         /**
1111          * This device received a negotiation request from another peer.
1112          *
1113          * Used in {@link #onConnectionRequested(int, WifiP2pConfig, WifiP2pDevice)}.
1114          */
1115         int REQUEST_TYPE_NEGOTIATION = 0;
1116         /**
1117          * This device received an invitation request from GO to join the group.
1118          *
1119          * Used in {@link #onConnectionRequested(int, WifiP2pConfig, WifiP2pDevice)}.
1120          */
1121         int REQUEST_TYPE_INVITATION = 1;
1122         /**
1123          * This GO device received a request from a peer to join the group.
1124          *
1125          * Used in {@link #onConnectionRequested(int, WifiP2pConfig, WifiP2pDevice)}.
1126          */
1127         int REQUEST_TYPE_JOIN = 2;
1128         /** @hide */
1129         @IntDef(prefix = {"REQUEST_TYPE__"}, value = {
1130             REQUEST_TYPE_NEGOTIATION,
1131             REQUEST_TYPE_INVITATION,
1132             REQUEST_TYPE_JOIN})
1133         @Retention(RetentionPolicy.SOURCE)
1134         public @interface RequestType {
1135         }
1136 
1137         /**
1138          * Detached by a call to
1139          * {@link #removeExternalApprover(Channel, MacAddress, ActionListener)}.
1140          *
1141          * Used in {@link #onDetached(MacAddress, int)}.
1142          */
1143         int APPROVER_DETACH_REASON_REMOVE = 0;
1144         /**
1145          * Detached due to a framework failure.
1146          *
1147          * Used in {@link #onDetached(MacAddress, int)}.
1148          */
1149         int APPROVER_DETACH_REASON_FAILURE = 1;
1150         /**
1151          * Detached when a new approver replaces an old one.
1152          *
1153          * Used in {@link #onDetached(MacAddress, int)}.
1154          */
1155         int APPROVER_DETACH_REASON_REPLACE = 2;
1156         /**
1157          * Detached since the {@link WifiP2pManager} channel was closed, e.g.
1158          * by using {@link Channel#close()} method.
1159          *
1160          * Used in {@link #onDetached(MacAddress, int)}.
1161          */
1162         int APPROVER_DETACH_REASON_CLOSE = 3;
1163         /** @hide */
1164         @IntDef(prefix = {"APPROVER_DETACH_REASON_"}, value = {
1165             APPROVER_DETACH_REASON_REMOVE,
1166             APPROVER_DETACH_REASON_FAILURE,
1167             APPROVER_DETACH_REASON_REPLACE,
1168             APPROVER_DETACH_REASON_CLOSE})
1169         @Retention(RetentionPolicy.SOURCE)
1170         public @interface ApproverDetachReason {
1171         }
1172 
1173         /**
1174          * Called when an approver registration via
1175          * {@link #addExternalApprover(Channel, MacAddress, ExternalApproverRequestListener)}
1176          * is successful.
1177          *
1178          * @param deviceAddress is the peer MAC address used in the registration.
1179          */
onAttached(@onNull MacAddress deviceAddress)1180         void onAttached(@NonNull MacAddress deviceAddress);
1181         /**
1182          * Called when an approver registration via
1183          * {@link #addExternalApprover(Channel, MacAddress, ExternalApproverRequestListener)}
1184          * has failed.
1185          *
1186          * @param deviceAddress is the peer MAC address used in the registration.
1187          * @param reason is the failure reason.
1188          */
onDetached(@onNull MacAddress deviceAddress, @ApproverDetachReason int reason)1189         void onDetached(@NonNull MacAddress deviceAddress, @ApproverDetachReason int reason);
1190         /**
1191          * Called when there is an incoming connection request
1192          * which matches a peer (identified by its {@link MacAddress}) registered by the external
1193          * approver through
1194          * {@link #addExternalApprover(Channel, MacAddress, ExternalApproverRequestListener)}.
1195          * The external approver is expected to follow up with a connection decision using the
1196          * {@link #setConnectionRequestResult(Channel, MacAddress, int, ActionListener)} with
1197          * {@link #CONNECTION_REQUEST_ACCEPT}, {@link #CONNECTION_REQUEST_REJECT}, or
1198          * {@link #CONNECTION_REQUEST_DEFER_TO_SERVICE}.
1199          *
1200          * @param requestType is one of {@link #REQUEST_TYPE_NEGOTIATION},
1201          *        {@link #REQUEST_TYPE_INVITATION}, and {@link #REQUEST_TYPE_JOIN}.
1202          * @param config is the peer configuration.
1203          * @param device is the peer information.
1204          */
onConnectionRequested( @equestType int requestType, @NonNull WifiP2pConfig config, @NonNull WifiP2pDevice device)1205         void onConnectionRequested(
1206                 @RequestType int requestType, @NonNull WifiP2pConfig config,
1207                 @NonNull WifiP2pDevice device);
1208         /**
1209          * Called when a PIN is generated by the WiFi service.
1210          *
1211          * The external approver can display the PIN, exchange the PIN via Out-Of-Band way
1212          * or ask the wifi service to show the PIN as usual using the
1213          * {@link #setConnectionRequestResult(Channel, MacAddress, int, ActionListener)}
1214          * with {@link #CONNECTION_REQUEST_DEFER_SHOW_PIN_TO_SERVICE}.
1215          *
1216          * @param deviceAddress is the peer MAC address used in the registration.
1217          * @param pin is the WPS PIN.
1218          */
onPinGenerated(@onNull MacAddress deviceAddress, @NonNull String pin)1219         void onPinGenerated(@NonNull MacAddress deviceAddress, @NonNull String pin);
1220     }
1221 
1222 
1223     /**
1224      * A channel that connects the application to the Wifi p2p framework.
1225      * Most p2p operations require a Channel as an argument. An instance of Channel is obtained
1226      * by doing a call on {@link #initialize}
1227      */
1228     public static class Channel implements AutoCloseable {
1229         /** @hide */
Channel(Context context, Looper looper, ChannelListener l, Binder binder, WifiP2pManager p2pManager)1230         public Channel(Context context, Looper looper, ChannelListener l, Binder binder,
1231                 WifiP2pManager p2pManager) {
1232             mAsyncChannel = new AsyncChannel();
1233             mHandler = new P2pHandler(looper);
1234             mChannelListener = l;
1235             mContext = context;
1236             mBinder = binder;
1237             mP2pManager = p2pManager;
1238 
1239             mCloseGuard.open("close");
1240         }
1241         private final static int INVALID_LISTENER_KEY = 0;
1242         private final WifiP2pManager mP2pManager;
1243         private ChannelListener mChannelListener;
1244         private ServiceResponseListener mServRspListener;
1245         private DnsSdServiceResponseListener mDnsSdServRspListener;
1246         private DnsSdTxtRecordListener mDnsSdTxtListener;
1247         private UpnpServiceResponseListener mUpnpServRspListener;
1248         private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>();
1249         private final Object mListenerMapLock = new Object();
1250         private int mListenerKey = 0;
1251 
1252         private final CloseGuard mCloseGuard = new CloseGuard();
1253 
1254         /**
1255          * Return the binder object.
1256          * @hide
1257          */
getBinder()1258         public @NonNull Binder getBinder() {
1259             return mBinder;
1260         }
1261 
1262         /**
1263          * Close the current P2P connection and indicate to the P2P service that connections
1264          * created by the app can be removed.
1265          */
close()1266         public void close() {
1267             if (mP2pManager == null) {
1268                 Log.w(TAG, "Channel.close(): Null mP2pManager!?");
1269             } else {
1270                 try {
1271                     mP2pManager.mService.close(mBinder);
1272                 } catch (RemoteException e) {
1273                     throw e.rethrowFromSystemServer();
1274                 }
1275             }
1276 
1277             mAsyncChannel.disconnect();
1278             mCloseGuard.close();
1279             Reference.reachabilityFence(this);
1280         }
1281 
1282         /** @hide */
1283         @Override
finalize()1284         protected void finalize() throws Throwable {
1285             try {
1286                 if (mCloseGuard != null) {
1287                     mCloseGuard.warnIfOpen();
1288                 }
1289 
1290                 close();
1291             } finally {
1292                 super.finalize();
1293             }
1294         }
1295 
1296         /* package */ final Binder mBinder;
1297 
1298         @UnsupportedAppUsage
1299         private AsyncChannel mAsyncChannel;
1300         private P2pHandler mHandler;
1301         Context mContext;
1302         class P2pHandler extends Handler {
P2pHandler(Looper looper)1303             P2pHandler(Looper looper) {
1304                 super(looper);
1305             }
1306 
1307             @Override
handleMessage(Message message)1308             public void handleMessage(Message message) {
1309                 Object listener = null;
1310                 // The listener for an external approver should be
1311                 // removed after detaching from the service.
1312                 switch (message.what) {
1313                     case EXTERNAL_APPROVER_ATTACH:
1314                     case EXTERNAL_APPROVER_CONNECTION_REQUESTED:
1315                     case EXTERNAL_APPROVER_PIN_GENERATED:
1316                         listener = getListener(message.arg2);
1317                         break;
1318                     default:
1319                         listener = removeListener(message.arg2);
1320                         break;
1321                 }
1322                 switch (message.what) {
1323                     case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
1324                         if (mChannelListener != null) {
1325                             mChannelListener.onChannelDisconnected();
1326                             mChannelListener = null;
1327                         }
1328                         break;
1329                     /* ActionListeners grouped together */
1330                     case DISCOVER_PEERS_FAILED:
1331                     case STOP_DISCOVERY_FAILED:
1332                     case DISCOVER_SERVICES_FAILED:
1333                     case CONNECT_FAILED:
1334                     case CANCEL_CONNECT_FAILED:
1335                     case CREATE_GROUP_FAILED:
1336                     case REMOVE_GROUP_FAILED:
1337                     case ADD_LOCAL_SERVICE_FAILED:
1338                     case REMOVE_LOCAL_SERVICE_FAILED:
1339                     case CLEAR_LOCAL_SERVICES_FAILED:
1340                     case ADD_SERVICE_REQUEST_FAILED:
1341                     case REMOVE_SERVICE_REQUEST_FAILED:
1342                     case CLEAR_SERVICE_REQUESTS_FAILED:
1343                     case SET_DEVICE_NAME_FAILED:
1344                     case DELETE_PERSISTENT_GROUP_FAILED:
1345                     case SET_WFD_INFO_FAILED:
1346                     case START_WPS_FAILED:
1347                     case START_LISTEN_FAILED:
1348                     case STOP_LISTEN_FAILED:
1349                     case GET_LISTEN_STATE_FAILED:
1350                     case SET_CHANNEL_FAILED:
1351                     case REPORT_NFC_HANDOVER_FAILED:
1352                     case FACTORY_RESET_FAILED:
1353                     case SET_ONGOING_PEER_CONFIG_FAILED:
1354                     case REMOVE_CLIENT_FAILED:
1355                     case REMOVE_EXTERNAL_APPROVER_FAILED:
1356                     case SET_CONNECTION_REQUEST_RESULT_FAILED:
1357                     case SET_VENDOR_ELEMENTS_FAILED:
1358                         if (listener != null) {
1359                             ((ActionListener) listener).onFailure(message.arg1);
1360                         }
1361                         break;
1362                     /* ActionListeners grouped together */
1363                     case DISCOVER_PEERS_SUCCEEDED:
1364                     case STOP_DISCOVERY_SUCCEEDED:
1365                     case DISCOVER_SERVICES_SUCCEEDED:
1366                     case CONNECT_SUCCEEDED:
1367                     case CANCEL_CONNECT_SUCCEEDED:
1368                     case CREATE_GROUP_SUCCEEDED:
1369                     case REMOVE_GROUP_SUCCEEDED:
1370                     case ADD_LOCAL_SERVICE_SUCCEEDED:
1371                     case REMOVE_LOCAL_SERVICE_SUCCEEDED:
1372                     case CLEAR_LOCAL_SERVICES_SUCCEEDED:
1373                     case ADD_SERVICE_REQUEST_SUCCEEDED:
1374                     case REMOVE_SERVICE_REQUEST_SUCCEEDED:
1375                     case CLEAR_SERVICE_REQUESTS_SUCCEEDED:
1376                     case SET_DEVICE_NAME_SUCCEEDED:
1377                     case DELETE_PERSISTENT_GROUP_SUCCEEDED:
1378                     case SET_WFD_INFO_SUCCEEDED:
1379                     case START_WPS_SUCCEEDED:
1380                     case START_LISTEN_SUCCEEDED:
1381                     case STOP_LISTEN_SUCCEEDED:
1382                     case SET_CHANNEL_SUCCEEDED:
1383                     case REPORT_NFC_HANDOVER_SUCCEEDED:
1384                     case FACTORY_RESET_SUCCEEDED:
1385                     case SET_ONGOING_PEER_CONFIG_SUCCEEDED:
1386                     case REMOVE_CLIENT_SUCCEEDED:
1387                     case REMOVE_EXTERNAL_APPROVER_SUCCEEDED:
1388                     case SET_CONNECTION_REQUEST_RESULT_SUCCEEDED:
1389                     case SET_VENDOR_ELEMENTS_SUCCEEDED:
1390                         if (listener != null) {
1391                             ((ActionListener) listener).onSuccess();
1392                         }
1393                         break;
1394                     case RESPONSE_PEERS:
1395                         WifiP2pDeviceList peers = (WifiP2pDeviceList) message.obj;
1396                         if (listener != null) {
1397                             ((PeerListListener) listener).onPeersAvailable(peers);
1398                         }
1399                         break;
1400                     case RESPONSE_CONNECTION_INFO:
1401                         WifiP2pInfo wifiP2pInfo = (WifiP2pInfo) message.obj;
1402                         if (listener != null) {
1403                             ((ConnectionInfoListener) listener).onConnectionInfoAvailable(wifiP2pInfo);
1404                         }
1405                         break;
1406                     case RESPONSE_GROUP_INFO:
1407                         WifiP2pGroup group = (WifiP2pGroup) message.obj;
1408                         if (listener != null) {
1409                             ((GroupInfoListener) listener).onGroupInfoAvailable(group);
1410                         }
1411                         break;
1412                     case RESPONSE_SERVICE:
1413                         WifiP2pServiceResponse resp = (WifiP2pServiceResponse) message.obj;
1414                         handleServiceResponse(resp);
1415                         break;
1416                     case RESPONSE_PERSISTENT_GROUP_INFO:
1417                         WifiP2pGroupList groups = (WifiP2pGroupList) message.obj;
1418                         if (listener != null) {
1419                             ((PersistentGroupInfoListener) listener).
1420                                 onPersistentGroupInfoAvailable(groups);
1421                         }
1422                         break;
1423                     case RESPONSE_GET_HANDOVER_MESSAGE:
1424                         Bundle handoverBundle = (Bundle) message.obj;
1425                         if (listener != null) {
1426                             String handoverMessage = handoverBundle != null
1427                                     ? handoverBundle.getString(EXTRA_HANDOVER_MESSAGE)
1428                                     : null;
1429                             ((HandoverMessageListener) listener)
1430                                     .onHandoverMessageAvailable(handoverMessage);
1431                         }
1432                         break;
1433                     case RESPONSE_ONGOING_PEER_CONFIG:
1434                         WifiP2pConfig peerConfig = (WifiP2pConfig) message.obj;
1435                         if (listener != null) {
1436                             ((OngoingPeerInfoListener) listener)
1437                                     .onOngoingPeerAvailable(peerConfig);
1438                         }
1439                         break;
1440                     case RESPONSE_P2P_STATE:
1441                         if (listener != null) {
1442                             ((P2pStateListener) listener)
1443                                     .onP2pStateAvailable(message.arg1);
1444                         }
1445                         break;
1446                     case RESPONSE_DISCOVERY_STATE:
1447                         if (listener != null) {
1448                             ((DiscoveryStateListener) listener)
1449                                     .onDiscoveryStateAvailable(message.arg1);
1450                         }
1451                         break;
1452                     case RESPONSE_GET_LISTEN_STATE:
1453                         if (listener != null) {
1454                             ((ListenStateListener) listener)
1455                                     .onListenStateAvailable(message.arg1);
1456                         }
1457                         break;
1458                     case RESPONSE_NETWORK_INFO:
1459                         if (listener != null) {
1460                             ((NetworkInfoListener) listener)
1461                                     .onNetworkInfoAvailable((NetworkInfo) message.obj);
1462                         }
1463                         break;
1464                     case RESPONSE_DEVICE_INFO:
1465                         if (listener != null) {
1466                             ((DeviceInfoListener) listener)
1467                                     .onDeviceInfoAvailable((WifiP2pDevice) message.obj);
1468                         }
1469                         break;
1470                     case EXTERNAL_APPROVER_ATTACH:
1471                         if (listener != null) {
1472                             ((ExternalApproverRequestListener) listener)
1473                                     .onAttached((MacAddress) message.obj);
1474                         }
1475                         break;
1476                     case EXTERNAL_APPROVER_DETACH:
1477                         if (listener != null) {
1478                             ((ExternalApproverRequestListener) listener)
1479                                     .onDetached((MacAddress) message.obj, message.arg1);
1480                         }
1481                         break;
1482                     case EXTERNAL_APPROVER_CONNECTION_REQUESTED:
1483                         if (listener != null) {
1484                             int requestType = message.arg1;
1485                             Bundle bundle = (Bundle) message.obj;
1486                             WifiP2pDevice device = bundle.getParcelable(EXTRA_PARAM_KEY_DEVICE);
1487                             WifiP2pConfig config = bundle.getParcelable(EXTRA_PARAM_KEY_CONFIG);
1488                             ((ExternalApproverRequestListener) listener)
1489                                     .onConnectionRequested(requestType, config, device);
1490                         }
1491                         break;
1492                     case EXTERNAL_APPROVER_PIN_GENERATED:
1493                         if (listener != null) {
1494                             Bundle bundle = (Bundle) message.obj;
1495                             MacAddress deviceAddress = bundle.getParcelable(
1496                                     EXTRA_PARAM_KEY_PEER_ADDRESS);
1497                             String pin = bundle.getString(EXTRA_PARAM_KEY_WPS_PIN);
1498                             ((ExternalApproverRequestListener) listener)
1499                                     .onPinGenerated(deviceAddress, pin);
1500                         }
1501                         break;
1502                     default:
1503                         Log.d(TAG, "Ignored " + message);
1504                         break;
1505                 }
1506             }
1507         }
1508 
handleServiceResponse(WifiP2pServiceResponse resp)1509         private void handleServiceResponse(WifiP2pServiceResponse resp) {
1510             if (resp instanceof WifiP2pDnsSdServiceResponse) {
1511                 handleDnsSdServiceResponse((WifiP2pDnsSdServiceResponse)resp);
1512             } else if (resp instanceof WifiP2pUpnpServiceResponse) {
1513                 if (mUpnpServRspListener != null) {
1514                     handleUpnpServiceResponse((WifiP2pUpnpServiceResponse)resp);
1515                 }
1516             } else {
1517                 if (mServRspListener != null) {
1518                     mServRspListener.onServiceAvailable(resp.getServiceType(),
1519                             resp.getRawData(), resp.getSrcDevice());
1520                 }
1521             }
1522         }
1523 
handleUpnpServiceResponse(WifiP2pUpnpServiceResponse resp)1524         private void handleUpnpServiceResponse(WifiP2pUpnpServiceResponse resp) {
1525             mUpnpServRspListener.onUpnpServiceAvailable(resp.getUniqueServiceNames(),
1526                     resp.getSrcDevice());
1527         }
1528 
handleDnsSdServiceResponse(WifiP2pDnsSdServiceResponse resp)1529         private void handleDnsSdServiceResponse(WifiP2pDnsSdServiceResponse resp) {
1530             if (resp.getDnsType() == WifiP2pDnsSdServiceInfo.DNS_TYPE_PTR) {
1531                 if (mDnsSdServRspListener != null) {
1532                     mDnsSdServRspListener.onDnsSdServiceAvailable(
1533                             resp.getInstanceName(),
1534                             resp.getDnsQueryName(),
1535                             resp.getSrcDevice());
1536                 }
1537             } else if (resp.getDnsType() == WifiP2pDnsSdServiceInfo.DNS_TYPE_TXT) {
1538                 if (mDnsSdTxtListener != null) {
1539                     mDnsSdTxtListener.onDnsSdTxtRecordAvailable(
1540                             resp.getDnsQueryName(),
1541                             resp.getTxtRecord(),
1542                             resp.getSrcDevice());
1543                 }
1544             } else {
1545                 Log.e(TAG, "Unhandled resp " + resp);
1546             }
1547         }
1548 
1549         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
putListener(Object listener)1550         private int putListener(Object listener) {
1551             if (listener == null) return INVALID_LISTENER_KEY;
1552             int key;
1553             synchronized (mListenerMapLock) {
1554                 do {
1555                     key = mListenerKey++;
1556                 } while (key == INVALID_LISTENER_KEY);
1557                 mListenerMap.put(key, listener);
1558             }
1559             return key;
1560         }
1561 
getListener(int key)1562         private Object getListener(int key) {
1563             if (key == INVALID_LISTENER_KEY) return null;
1564             synchronized (mListenerMapLock) {
1565                 return mListenerMap.get(key);
1566             }
1567         }
1568 
removeListener(int key)1569         private Object removeListener(int key) {
1570             if (key == INVALID_LISTENER_KEY) return null;
1571             synchronized (mListenerMapLock) {
1572                 return mListenerMap.remove(key);
1573             }
1574         }
1575     }
1576 
checkChannel(Channel c)1577     private static void checkChannel(Channel c) {
1578         if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
1579     }
1580 
checkServiceInfo(WifiP2pServiceInfo info)1581     private static void checkServiceInfo(WifiP2pServiceInfo info) {
1582         if (info == null) throw new IllegalArgumentException("service info is null");
1583     }
1584 
checkServiceRequest(WifiP2pServiceRequest req)1585     private static void checkServiceRequest(WifiP2pServiceRequest req) {
1586         if (req == null) throw new IllegalArgumentException("service request is null");
1587     }
1588 
checkP2pConfig(WifiP2pConfig c)1589     private void checkP2pConfig(WifiP2pConfig c) {
1590         if (c == null) throw new IllegalArgumentException("config cannot be null");
1591         if (TextUtils.isEmpty(c.deviceAddress)) {
1592             throw new IllegalArgumentException("deviceAddress cannot be empty");
1593         }
1594     }
1595 
1596     /**
1597      * Registers the application with the Wi-Fi framework. This function
1598      * must be the first to be called before any p2p operations are performed.
1599      *
1600      * @param srcContext is the context of the source
1601      * @param srcLooper is the Looper on which the callbacks are receivied
1602      * @param listener for callback at loss of framework communication. Can be null.
1603      * @return Channel instance that is necessary for performing any further p2p operations
1604      */
initialize(Context srcContext, Looper srcLooper, ChannelListener listener)1605     public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
1606         Binder binder = new Binder();
1607         Bundle extras = prepareExtrasBundleWithAttributionSource(srcContext);
1608         int displayId = Display.DEFAULT_DISPLAY;
1609         try {
1610             Display display = srcContext.getDisplay();
1611             if (display != null) {
1612                 displayId = display.getDisplayId();
1613             }
1614         } catch (UnsupportedOperationException e) {
1615             // an acceptable (per API definition) result of getDisplay - implying there's no display
1616             // associated with the context
1617         }
1618         extras.putInt(EXTRA_PARAM_KEY_DISPLAY_ID, displayId);
1619         Channel channel = initializeChannel(srcContext, srcLooper, listener,
1620                 getMessenger(binder, srcContext.getOpPackageName(), extras), binder);
1621         return channel;
1622     }
1623 
1624     /**
1625      * Registers the application with the Wi-Fi framework. Enables system-only functionality.
1626      * @hide
1627      */
initializeInternal(Context srcContext, Looper srcLooper, ChannelListener listener)1628     public Channel initializeInternal(Context srcContext, Looper srcLooper,
1629                                       ChannelListener listener) {
1630         return initializeChannel(srcContext, srcLooper, listener, getP2pStateMachineMessenger(),
1631                 null);
1632     }
1633 
prepareMessage(int what, int arg1, int arg2, Bundle extras, Context context)1634     private Message prepareMessage(int what, int arg1, int arg2, Bundle extras, Context context) {
1635         Message msg = Message.obtain();
1636         msg.what = what;
1637         msg.arg1 = arg1;
1638         msg.arg2 = arg2;
1639         msg.obj = maybeGetAttributionSource(context);
1640         msg.getData().putBundle(EXTRA_PARAM_KEY_BUNDLE, extras);
1641         return msg;
1642     }
1643 
prepareExtrasBundle(Channel c)1644     private Bundle prepareExtrasBundle(Channel c) {
1645         Bundle b = new Bundle();
1646         b.putBinder(CALLING_BINDER, c.getBinder());
1647         return b;
1648     }
1649 
1650     /**
1651      * Note, this should only be used for Binder calls.
1652      * Unparcelling an AttributionSource will throw an exception when done outside of a Binder
1653      * transaction. So don't use this with AsyncChannel since it will throw exception when
1654      * unparcelling.
1655      */
prepareExtrasBundleWithAttributionSource(Context context)1656     private Bundle prepareExtrasBundleWithAttributionSource(Context context) {
1657         Bundle bundle = new Bundle();
1658         if (SdkLevel.isAtLeastS()) {
1659             bundle.putParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
1660                     context.getAttributionSource());
1661         }
1662         return bundle;
1663     }
1664 
maybeGetAttributionSource(Context context)1665     private Object maybeGetAttributionSource(Context context) {
1666         return SdkLevel.isAtLeastS() ? context.getAttributionSource() : null;
1667     }
1668 
initializeChannel(Context srcContext, Looper srcLooper, ChannelListener listener, Messenger messenger, Binder binder)1669     private Channel initializeChannel(Context srcContext, Looper srcLooper,
1670             ChannelListener listener, Messenger messenger, Binder binder) {
1671         if (messenger == null) return null;
1672 
1673         Channel c = new Channel(srcContext, srcLooper, listener, binder, this);
1674         if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger)
1675                 == AsyncChannel.STATUS_SUCCESSFUL) {
1676             Bundle bundle = new Bundle();
1677             bundle.putString(CALLING_PACKAGE, c.mContext.getOpPackageName());
1678             bundle.putString(CALLING_FEATURE_ID, c.mContext.getAttributionTag());
1679             bundle.putBinder(CALLING_BINDER, binder);
1680             Message msg = prepareMessage(UPDATE_CHANNEL_INFO, 0, c.putListener(null),
1681                     bundle, c.mContext);
1682             c.mAsyncChannel.sendMessage(msg);
1683             return c;
1684         } else {
1685             c.close();
1686             return null;
1687         }
1688     }
1689 
1690     /**
1691      * Initiate peer discovery. A discovery process involves scanning for available Wi-Fi peers
1692      * for the purpose of establishing a connection.
1693      *
1694      * <p> The function call immediately returns after sending a discovery request
1695      * to the framework. The application is notified of a success or failure to initiate
1696      * discovery through listener callbacks {@link ActionListener#onSuccess} or
1697      * {@link ActionListener#onFailure}.
1698      *
1699      * <p> The discovery remains active until a connection is initiated or
1700      * a p2p group is formed. Register for {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent to
1701      * determine when the framework notifies of a change as peers are discovered.
1702      *
1703      * <p> Upon receiving a {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent, an application
1704      * can request the list of peers using {@link #requestPeers}.
1705      * <p>
1706      * If targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later, the application must
1707      * have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
1708      * android:usesPermissionFlags="neverForLocation". If the application does not declare
1709      * android:usesPermissionFlags="neverForLocation", then it must also have
1710      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
1711      *
1712      * If targeting an earlier release than {@link android.os.Build.VERSION_CODES#TIRAMISU}, the
1713      * application must have {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
1714      *
1715      * @param channel is the channel created at {@link #initialize}
1716      * @param listener for callbacks on success or failure. Can be null.
1717      */
1718     @RequiresPermission(allOf = {
1719             android.Manifest.permission.NEARBY_WIFI_DEVICES,
1720             android.Manifest.permission.ACCESS_FINE_LOCATION
1721             }, conditional = true)
discoverPeers(Channel channel, ActionListener listener)1722     public void discoverPeers(Channel channel, ActionListener listener) {
1723         checkChannel(channel);
1724         Bundle extras = prepareExtrasBundle(channel);
1725         channel.mAsyncChannel.sendMessage(prepareMessage(DISCOVER_PEERS, WIFI_P2P_SCAN_FULL,
1726                 channel.putListener(listener), extras, channel.mContext));
1727     }
1728 
1729     /**
1730      * Scan only the social channels.
1731      *
1732      * A discovery process involves scanning for available Wi-Fi peers
1733      * for the purpose of establishing a connection.
1734      *
1735      * <p> The function call immediately returns after sending a discovery request
1736      * to the framework. The application is notified of a success or failure to initiate
1737      * discovery through listener callbacks {@link ActionListener#onSuccess} or
1738      * {@link ActionListener#onFailure}.
1739      *
1740      * <p> The discovery remains active until a connection is initiated or
1741      * a p2p group is formed. Register for {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent to
1742      * determine when the framework notifies of a change as peers are discovered.
1743      *
1744      * <p> Upon receiving a {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent, an application
1745      * can request the list of peers using {@link #requestPeers}.
1746      * <p>
1747      * The application must have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
1748      * android:usesPermissionFlags="neverForLocation". If the application does not declare
1749      * android:usesPermissionFlags="neverForLocation", then it must also have
1750      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
1751      * <p>
1752      * Use {@link #isChannelConstrainedDiscoverySupported()} to determine whether the device
1753      * supports this feature. If {@link #isChannelConstrainedDiscoverySupported()} return
1754      * {@code false} then this method will throw {@link UnsupportedOperationException}.
1755      *
1756      * @param channel is the channel created at {@link #initialize}
1757      * @param listener for callbacks on success or failure.
1758      */
1759     @RequiresPermission(allOf = {
1760             android.Manifest.permission.NEARBY_WIFI_DEVICES,
1761             android.Manifest.permission.ACCESS_FINE_LOCATION
1762             }, conditional = true)
discoverPeersOnSocialChannels(@onNull Channel channel, @Nullable ActionListener listener)1763     public void discoverPeersOnSocialChannels(@NonNull Channel channel,
1764             @Nullable ActionListener listener) {
1765         if (!isChannelConstrainedDiscoverySupported()) {
1766             throw new UnsupportedOperationException();
1767         }
1768         checkChannel(channel);
1769         Bundle extras = prepareExtrasBundle(channel);
1770         channel.mAsyncChannel.sendMessage(prepareMessage(DISCOVER_PEERS, WIFI_P2P_SCAN_SOCIAL,
1771                 channel.putListener(listener), extras, channel.mContext));
1772     }
1773 
1774     /**
1775      * Scan only a single channel specified by frequency.
1776      *
1777      * A discovery process involves scanning for available Wi-Fi peers
1778      * for the purpose of establishing a connection.
1779      *
1780      * <p> The function call immediately returns after sending a discovery request
1781      * to the framework. The application is notified of a success or failure to initiate
1782      * discovery through listener callbacks {@link ActionListener#onSuccess} or
1783      * {@link ActionListener#onFailure}.
1784      *
1785      * <p> The discovery remains active until a connection is initiated or
1786      * a p2p group is formed. Register for {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent to
1787      * determine when the framework notifies of a change as peers are discovered.
1788      *
1789      * <p> Upon receiving a {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent, an application
1790      * can request the list of peers using {@link #requestPeers}.
1791      * <p>
1792      * The application must have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
1793      * android:usesPermissionFlags="neverForLocation". If the application does not declare
1794      * android:usesPermissionFlags="neverForLocation", then it must also have
1795      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
1796      * <p>
1797      * Use {@link #isChannelConstrainedDiscoverySupported()} to determine whether the device
1798      * supports this feature. If {@link #isChannelConstrainedDiscoverySupported()} return
1799      * {@code false} then this method will throw {@link UnsupportedOperationException}.
1800      *
1801      * @param channel is the channel created at {@link #initialize}
1802      * @param frequencyMhz is the frequency of the channel to use for peer discovery.
1803      * @param listener for callbacks on success or failure.
1804      */
1805     @RequiresPermission(allOf = {
1806             android.Manifest.permission.NEARBY_WIFI_DEVICES,
1807             android.Manifest.permission.ACCESS_FINE_LOCATION
1808             }, conditional = true)
discoverPeersOnSpecificFrequency( @onNull Channel channel, int frequencyMhz, @Nullable ActionListener listener)1809     public void discoverPeersOnSpecificFrequency(
1810             @NonNull Channel channel, int frequencyMhz, @Nullable ActionListener listener) {
1811         if (!isChannelConstrainedDiscoverySupported()) {
1812             throw new UnsupportedOperationException();
1813         }
1814         checkChannel(channel);
1815         if (frequencyMhz <= 0) {
1816             throw new IllegalArgumentException("This frequency must be a positive value.");
1817         }
1818         Bundle extras = prepareExtrasBundle(channel);
1819         extras.putInt(EXTRA_PARAM_KEY_PEER_DISCOVERY_FREQ, frequencyMhz);
1820         channel.mAsyncChannel.sendMessage(prepareMessage(DISCOVER_PEERS, WIFI_P2P_SCAN_SINGLE_FREQ,
1821                 channel.putListener(listener), extras, channel.mContext));
1822     }
1823 
1824     /**
1825      * Stop an ongoing peer discovery
1826      *
1827      * <p> The function call immediately returns after sending a stop request
1828      * to the framework. The application is notified of a success or failure to initiate
1829      * stop through listener callbacks {@link ActionListener#onSuccess} or
1830      * {@link ActionListener#onFailure}.
1831      *
1832      * <p> If P2P Group is in the process of being created, this call will fail (report failure via
1833      * {@code listener}. The applicantion should listen to
1834      * {@link #WIFI_P2P_CONNECTION_CHANGED_ACTION} to ensure the state is not
1835      * {@link android.net.NetworkInfo.State#CONNECTING} and repeat calling when the state changes.
1836      *
1837      * @param channel is the channel created at {@link #initialize}
1838      * @param listener for callbacks on success or failure. Can be null.
1839      */
stopPeerDiscovery(Channel channel, ActionListener listener)1840     public void stopPeerDiscovery(Channel channel, ActionListener listener) {
1841         checkChannel(channel);
1842         channel.mAsyncChannel.sendMessage(STOP_DISCOVERY, 0, channel.putListener(listener));
1843     }
1844 
1845     /**
1846      * Start a p2p connection to a device with the specified configuration.
1847      *
1848      * <p> The function call immediately returns after sending a connection request
1849      * to the framework. The application is notified of a success or failure to initiate
1850      * connect through listener callbacks {@link ActionListener#onSuccess} or
1851      * {@link ActionListener#onFailure}.
1852      *
1853      * <p> An app should use {@link WifiP2pConfig.Builder} to build the configuration
1854      * for this API, ex. call {@link WifiP2pConfig.Builder#setDeviceAddress(MacAddress)}
1855      * to set the peer MAC address and {@link WifiP2pConfig.Builder#enablePersistentMode(boolean)}
1856      * to configure the persistent mode.
1857      *
1858      * <p> Register for {@link #WIFI_P2P_CONNECTION_CHANGED_ACTION} intent to
1859      * determine when the framework notifies of a change in connectivity.
1860      *
1861      * <p> If the current device is not part of a p2p group, a connect request initiates
1862      * a group negotiation with the peer.
1863      *
1864      * <p> If the current device is part of an existing p2p group or has created
1865      * a p2p group with {@link #createGroup}, an invitation to join the group is sent to
1866      * the peer device.
1867      * <p>
1868      * If targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later, the application must
1869      * have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
1870      * android:usesPermissionFlags="neverForLocation". If the application does not declare
1871      * android:usesPermissionFlags="neverForLocation", then it must also have
1872      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
1873      *
1874      * If targeting an earlier release than {@link android.os.Build.VERSION_CODES#TIRAMISU}, the
1875      * application must have {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
1876      *
1877      * @param channel is the channel created at {@link #initialize}
1878      * @param config options as described in {@link WifiP2pConfig} class
1879      * @param listener for callbacks on success or failure. Can be null.
1880      */
1881     @RequiresPermission(allOf = {
1882             android.Manifest.permission.NEARBY_WIFI_DEVICES,
1883             android.Manifest.permission.ACCESS_FINE_LOCATION
1884             }, conditional = true)
connect(Channel channel, WifiP2pConfig config, ActionListener listener)1885     public void connect(Channel channel, WifiP2pConfig config, ActionListener listener) {
1886         checkChannel(channel);
1887         checkP2pConfig(config);
1888         Bundle extras = prepareExtrasBundle(channel);
1889         extras.putParcelable(EXTRA_PARAM_KEY_CONFIG, config);
1890         channel.mAsyncChannel.sendMessage(prepareMessage(CONNECT, 0, channel.putListener(listener),
1891                 extras, channel.mContext));
1892     }
1893 
1894     /**
1895      * Cancel any ongoing p2p group negotiation
1896      *
1897      * <p> The function call immediately returns after sending a connection cancellation request
1898      * to the framework. The application is notified of a success or failure to initiate
1899      * cancellation through listener callbacks {@link ActionListener#onSuccess} or
1900      * {@link ActionListener#onFailure}.
1901      *
1902      * @param channel is the channel created at {@link #initialize}
1903      * @param listener for callbacks on success or failure. Can be null.
1904      */
cancelConnect(Channel channel, ActionListener listener)1905     public void cancelConnect(Channel channel, ActionListener listener) {
1906         checkChannel(channel);
1907         channel.mAsyncChannel.sendMessage(CANCEL_CONNECT, 0, channel.putListener(listener));
1908     }
1909 
1910     /**
1911      * Create a p2p group with the current device as the group owner. This essentially creates
1912      * an access point that can accept connections from legacy clients as well as other p2p
1913      * devices.
1914      *
1915      * <p class="note"><strong>Note:</strong>
1916      * This function would normally not be used unless the current device needs
1917      * to form a p2p connection with a legacy client
1918      *
1919      * <p> The function call immediately returns after sending a group creation request
1920      * to the framework. The application is notified of a success or failure to initiate
1921      * group creation through listener callbacks {@link ActionListener#onSuccess} or
1922      * {@link ActionListener#onFailure}.
1923      *
1924      * <p> Application can request for the group details with {@link #requestGroupInfo}.
1925      * <p>
1926      * If targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later, the application must
1927      * have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
1928      * android:usesPermissionFlags="neverForLocation". If the application does not declare
1929      * android:usesPermissionFlags="neverForLocation", then it must also have
1930      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
1931      *
1932      * If targeting an earlier release than {@link android.os.Build.VERSION_CODES#TIRAMISU}, the
1933      * application must have {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
1934      *
1935      * @param channel is the channel created at {@link #initialize}
1936      * @param listener for callbacks on success or failure. Can be null.
1937      */
1938     @RequiresPermission(allOf = {
1939             android.Manifest.permission.NEARBY_WIFI_DEVICES,
1940             android.Manifest.permission.ACCESS_FINE_LOCATION
1941             }, conditional = true)
createGroup(Channel channel, ActionListener listener)1942     public void createGroup(Channel channel, ActionListener listener) {
1943         checkChannel(channel);
1944         Bundle extras = prepareExtrasBundle(channel);
1945         channel.mAsyncChannel.sendMessage(prepareMessage(CREATE_GROUP,
1946                 WifiP2pGroup.NETWORK_ID_PERSISTENT, channel.putListener(listener), extras,
1947                 channel.mContext));
1948     }
1949 
1950     /**
1951      * Create a p2p group with the current device as the group owner. This essentially creates
1952      * an access point that can accept connections from legacy clients as well as other p2p
1953      * devices.
1954      *
1955      * <p> An app should use {@link WifiP2pConfig.Builder} to build the configuration
1956      * for a group.
1957      *
1958      * <p class="note"><strong>Note:</strong>
1959      * This function would normally not be used unless the current device needs
1960      * to form a p2p group as a Group Owner and allow peers to join it as either
1961      * Group Clients or legacy Wi-Fi STAs.
1962      *
1963      * <p> The function call immediately returns after sending a group creation request
1964      * to the framework. The application is notified of a success or failure to initiate
1965      * group creation through listener callbacks {@link ActionListener#onSuccess} or
1966      * {@link ActionListener#onFailure}.
1967      *
1968      * <p> Application can request for the group details with {@link #requestGroupInfo}.
1969      * <p>
1970      * If targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later, the application must
1971      * have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
1972      * android:usesPermissionFlags="neverForLocation". If the application does not declare
1973      * android:usesPermissionFlags="neverForLocation", then it must also have
1974      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
1975      *
1976      * If targeting an earlier release than {@link android.os.Build.VERSION_CODES#TIRAMISU}, the
1977      * application must have {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
1978      *
1979      * @param channel is the channel created at {@link #initialize}.
1980      * @param config the configuration of a p2p group.
1981      * @param listener for callbacks on success or failure. Can be null.
1982      */
1983     @RequiresPermission(allOf = {
1984             android.Manifest.permission.NEARBY_WIFI_DEVICES,
1985             android.Manifest.permission.ACCESS_FINE_LOCATION
1986             }, conditional = true)
createGroup(@onNull Channel channel, @Nullable WifiP2pConfig config, @Nullable ActionListener listener)1987     public void createGroup(@NonNull Channel channel,
1988             @Nullable WifiP2pConfig config,
1989             @Nullable ActionListener listener) {
1990         checkChannel(channel);
1991         Bundle extras = prepareExtrasBundle(channel);
1992         extras.putParcelable(EXTRA_PARAM_KEY_CONFIG, config);
1993         channel.mAsyncChannel.sendMessage(prepareMessage(CREATE_GROUP, 0,
1994                 channel.putListener(listener), extras, channel.mContext));
1995     }
1996 
1997     /**
1998      * Remove the current p2p group.
1999      *
2000      * <p> The function call immediately returns after sending a group removal request
2001      * to the framework. The application is notified of a success or failure to initiate
2002      * group removal through listener callbacks {@link ActionListener#onSuccess} or
2003      * {@link ActionListener#onFailure}.
2004      *
2005      * @param channel is the channel created at {@link #initialize}
2006      * @param listener for callbacks on success or failure. Can be null.
2007      */
removeGroup(Channel channel, ActionListener listener)2008     public void removeGroup(Channel channel, ActionListener listener) {
2009         checkChannel(channel);
2010         channel.mAsyncChannel.sendMessage(REMOVE_GROUP, 0, channel.putListener(listener));
2011     }
2012 
2013     /**
2014      * Force p2p to enter listen state.
2015      *
2016      * When this API is called, this device will periodically enter LISTENING state until
2017      * {@link #stopListening(Channel, ActionListener)} or
2018      * {@link #stopPeerDiscovery(Channel, ActionListener)} are called.
2019      * While in LISTENING state, this device will dwell at its social channel and respond
2020      * to probe requests from other Wi-Fi Direct peers.
2021      * <p>
2022      * If targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later, the application must
2023      * have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
2024      * android:usesPermissionFlags="neverForLocation". If the application does not declare
2025      * android:usesPermissionFlags="neverForLocation", then it must also have
2026      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
2027      *
2028      * If targeting an earlier release than {@link android.os.Build.VERSION_CODES#TIRAMISU}, the
2029      * application must have {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
2030      * @param channel is the channel created at
2031      *    {@link #initialize(Context, Looper, ChannelListener)}
2032      * @param listener for callbacks on success or failure.
2033      */
2034     @RequiresPermission(allOf = {
2035             android.Manifest.permission.NEARBY_WIFI_DEVICES,
2036             android.Manifest.permission.ACCESS_FINE_LOCATION
2037             }, conditional = true)
startListening(@onNull Channel channel, @Nullable ActionListener listener)2038     public void startListening(@NonNull Channel channel, @Nullable ActionListener listener) {
2039         checkChannel(channel);
2040         Bundle extras = prepareExtrasBundle(channel);
2041         channel.mAsyncChannel.sendMessage(prepareMessage(START_LISTEN, 0,
2042                 channel.putListener(listener), extras, channel.mContext));
2043     }
2044 
2045     /**
2046      * Force p2p to exit listen state.
2047      *
2048      * When this API is called, this device will stop entering LISTENING state periodically
2049      * which is triggered by {@link #startListening(Channel, ActionListener)}.
2050      * If there are running peer discovery which is triggered by
2051      * {@link #discoverPeers(Channel, ActionListener)} or running service discovery which is
2052      * triggered by {@link #discoverServices(Channel, ActionListener)}, they will be stopped
2053      * as well.
2054      *
2055      * @param channel is the channel created at
2056      *    {@link #initialize(Context, Looper, ChannelListener)}
2057      * @param listener for callbacks on success or failure.
2058      */
stopListening(@onNull Channel channel, @Nullable ActionListener listener)2059     public void stopListening(@NonNull Channel channel, @Nullable ActionListener listener) {
2060         checkChannel(channel);
2061         channel.mAsyncChannel.sendMessage(STOP_LISTEN, 0, channel.putListener(listener));
2062     }
2063 
2064     /**
2065      * Set P2P listening and operating channel.
2066      *
2067      * @param channel is the channel created at {@link #initialize}
2068      * @param listeningChannel the listening channel's Wifi channel number. e.g. 1, 6, 11.
2069      * @param operatingChannel the operating channel's Wifi channel number. e.g. 1, 6, 11.
2070      * @param listener for callbacks on success or failure. Can be null.
2071      *
2072      * @hide
2073      */
2074     @SystemApi
2075     @RequiresPermission(anyOf = {
2076             android.Manifest.permission.NETWORK_SETTINGS,
2077             android.Manifest.permission.NETWORK_STACK,
2078             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
2079     })
setWifiP2pChannels(@onNull Channel channel, int listeningChannel, int operatingChannel, @Nullable ActionListener listener)2080     public void setWifiP2pChannels(@NonNull Channel channel, int listeningChannel,
2081             int operatingChannel, @Nullable ActionListener listener) {
2082         checkChannel(channel);
2083         Bundle p2pChannels = new Bundle();
2084         p2pChannels.putInt("lc", listeningChannel);
2085         p2pChannels.putInt("oc", operatingChannel);
2086         channel.mAsyncChannel.sendMessage(
2087                 SET_CHANNEL, 0, channel.putListener(listener), p2pChannels);
2088     }
2089 
2090     /**
2091      * Start a Wi-Fi Protected Setup (WPS) session.
2092      *
2093      * <p> The function call immediately returns after sending a request to start a
2094      * WPS session. Currently, this is only valid if the current device is running
2095      * as a group owner to allow any new clients to join the group. The application
2096      * is notified of a success or failure to initiate WPS through listener callbacks
2097      * {@link ActionListener#onSuccess} or {@link ActionListener#onFailure}.
2098      * @hide
2099      */
2100     @UnsupportedAppUsage(trackingBug = 185141982)
startWps(Channel channel, WpsInfo wps, ActionListener listener)2101     public void startWps(Channel channel, WpsInfo wps, ActionListener listener) {
2102         checkChannel(channel);
2103         channel.mAsyncChannel.sendMessage(START_WPS, 0, channel.putListener(listener), wps);
2104     }
2105 
2106     /**
2107      * Register a local service for service discovery. If a local service is registered,
2108      * the framework automatically responds to a service discovery request from a peer.
2109      *
2110      * <p> The function call immediately returns after sending a request to add a local
2111      * service to the framework. The application is notified of a success or failure to
2112      * add service through listener callbacks {@link ActionListener#onSuccess} or
2113      * {@link ActionListener#onFailure}.
2114      *
2115      * <p>The service information is set through {@link WifiP2pServiceInfo}.<br>
2116      * or its subclass calls  {@link WifiP2pUpnpServiceInfo#newInstance} or
2117      *  {@link WifiP2pDnsSdServiceInfo#newInstance} for a Upnp or Bonjour service
2118      * respectively
2119      *
2120      * <p>The service information can be cleared with calls to
2121      *  {@link #removeLocalService} or {@link #clearLocalServices}.
2122      * <p>
2123      * If targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later, the application must
2124      * have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
2125      * android:usesPermissionFlags="neverForLocation". If the application does not declare
2126      * android:usesPermissionFlags="neverForLocation", then it must also have
2127      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
2128      *
2129      * If targeting an earlier release than {@link android.os.Build.VERSION_CODES#TIRAMISU}, the
2130      * application must have {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
2131      *
2132      * @param channel is the channel created at {@link #initialize}
2133      * @param servInfo is a local service information.
2134      * @param listener for callbacks on success or failure. Can be null.
2135      */
2136     @RequiresPermission(allOf = {
2137             android.Manifest.permission.NEARBY_WIFI_DEVICES,
2138             android.Manifest.permission.ACCESS_FINE_LOCATION
2139             }, conditional = true)
addLocalService(Channel channel, WifiP2pServiceInfo servInfo, ActionListener listener)2140     public void addLocalService(Channel channel, WifiP2pServiceInfo servInfo,
2141             ActionListener listener) {
2142         checkChannel(channel);
2143         checkServiceInfo(servInfo);
2144         Bundle extras = prepareExtrasBundle(channel);
2145         extras.putParcelable(EXTRA_PARAM_KEY_SERVICE_INFO, servInfo);
2146         channel.mAsyncChannel.sendMessage(prepareMessage(ADD_LOCAL_SERVICE, 0,
2147                 channel.putListener(listener), extras, channel.mContext));
2148     }
2149 
2150     /**
2151      * Remove a registered local service added with {@link #addLocalService}
2152      *
2153      * <p> The function call immediately returns after sending a request to remove a
2154      * local service to the framework. The application is notified of a success or failure to
2155      * add service through listener callbacks {@link ActionListener#onSuccess} or
2156      * {@link ActionListener#onFailure}.
2157      *
2158      * @param channel is the channel created at {@link #initialize}
2159      * @param servInfo is the local service information.
2160      * @param listener for callbacks on success or failure. Can be null.
2161      */
removeLocalService(Channel channel, WifiP2pServiceInfo servInfo, ActionListener listener)2162     public void removeLocalService(Channel channel, WifiP2pServiceInfo servInfo,
2163             ActionListener listener) {
2164         checkChannel(channel);
2165         checkServiceInfo(servInfo);
2166         channel.mAsyncChannel.sendMessage(
2167                 REMOVE_LOCAL_SERVICE, 0, channel.putListener(listener), servInfo);
2168     }
2169 
2170     /**
2171      * Clear all registered local services of service discovery.
2172      *
2173      * <p> The function call immediately returns after sending a request to clear all
2174      * local services to the framework. The application is notified of a success or failure to
2175      * add service through listener callbacks {@link ActionListener#onSuccess} or
2176      * {@link ActionListener#onFailure}.
2177      *
2178      * @param channel is the channel created at {@link #initialize}
2179      * @param listener for callbacks on success or failure. Can be null.
2180      */
clearLocalServices(Channel channel, ActionListener listener)2181     public void clearLocalServices(Channel channel, ActionListener listener) {
2182         checkChannel(channel);
2183         channel.mAsyncChannel.sendMessage(CLEAR_LOCAL_SERVICES, 0, channel.putListener(listener));
2184     }
2185 
2186     /**
2187      * Register a callback to be invoked on receiving service discovery response.
2188      * Used only for vendor specific protocol right now. For Bonjour or Upnp, use
2189      * {@link #setDnsSdResponseListeners} or {@link #setUpnpServiceResponseListener}
2190      * respectively.
2191      *
2192      * <p> see {@link #discoverServices} for the detail.
2193      *
2194      * @param channel is the channel created at {@link #initialize}
2195      * @param listener for callbacks on receiving service discovery response.
2196      */
setServiceResponseListener(Channel channel, ServiceResponseListener listener)2197     public void setServiceResponseListener(Channel channel,
2198             ServiceResponseListener listener) {
2199         checkChannel(channel);
2200         channel.mServRspListener = listener;
2201     }
2202 
2203     /**
2204      * Register a callback to be invoked on receiving Bonjour service discovery
2205      * response.
2206      *
2207      * <p> see {@link #discoverServices} for the detail.
2208      *
2209      * @param channel
2210      * @param servListener is for listening to a Bonjour service response
2211      * @param txtListener is for listening to a Bonjour TXT record response
2212      */
setDnsSdResponseListeners(Channel channel, DnsSdServiceResponseListener servListener, DnsSdTxtRecordListener txtListener)2213     public void setDnsSdResponseListeners(Channel channel,
2214             DnsSdServiceResponseListener servListener, DnsSdTxtRecordListener txtListener) {
2215         checkChannel(channel);
2216         channel.mDnsSdServRspListener = servListener;
2217         channel.mDnsSdTxtListener = txtListener;
2218     }
2219 
2220     /**
2221      * Register a callback to be invoked on receiving upnp service discovery
2222      * response.
2223      *
2224      * <p> see {@link #discoverServices} for the detail.
2225      *
2226      * @param channel is the channel created at {@link #initialize}
2227      * @param listener for callbacks on receiving service discovery response.
2228      */
setUpnpServiceResponseListener(Channel channel, UpnpServiceResponseListener listener)2229     public void setUpnpServiceResponseListener(Channel channel,
2230             UpnpServiceResponseListener listener) {
2231         checkChannel(channel);
2232         channel.mUpnpServRspListener = listener;
2233     }
2234 
2235     /**
2236      * Initiate service discovery. A discovery process involves scanning for
2237      * requested services for the purpose of establishing a connection to a peer
2238      * that supports an available service.
2239      *
2240      * <p> The function call immediately returns after sending a request to start service
2241      * discovery to the framework. The application is notified of a success or failure to initiate
2242      * discovery through listener callbacks {@link ActionListener#onSuccess} or
2243      * {@link ActionListener#onFailure}.
2244      *
2245      * <p> The services to be discovered are specified with calls to {@link #addServiceRequest}.
2246      *
2247      * <p>The application is notified of the response against the service discovery request
2248      * through listener callbacks registered by {@link #setServiceResponseListener} or
2249      * {@link #setDnsSdResponseListeners}, or {@link #setUpnpServiceResponseListener}.
2250      * <p>
2251      * If targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later, the application must
2252      * have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
2253      * android:usesPermissionFlags="neverForLocation". If the application does not declare
2254      * android:usesPermissionFlags="neverForLocation", then it must also have
2255      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
2256      *
2257      * If targeting an earlier release than {@link android.os.Build.VERSION_CODES#TIRAMISU}, the
2258      * application must have {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
2259      *
2260      * @param channel is the channel created at {@link #initialize}
2261      * @param listener for callbacks on success or failure. Can be null.
2262      */
2263     @RequiresPermission(allOf = {
2264             android.Manifest.permission.NEARBY_WIFI_DEVICES,
2265             android.Manifest.permission.ACCESS_FINE_LOCATION
2266             }, conditional = true)
discoverServices(Channel channel, ActionListener listener)2267     public void discoverServices(Channel channel, ActionListener listener) {
2268         checkChannel(channel);
2269         Bundle extras = prepareExtrasBundle(channel);
2270         channel.mAsyncChannel.sendMessage(prepareMessage(DISCOVER_SERVICES, 0,
2271                 channel.putListener(listener), extras, channel.mContext));
2272     }
2273 
2274     /**
2275      * Add a service discovery request.
2276      *
2277      * <p> The function call immediately returns after sending a request to add service
2278      * discovery request to the framework. The application is notified of a success or failure to
2279      * add service through listener callbacks {@link ActionListener#onSuccess} or
2280      * {@link ActionListener#onFailure}.
2281      *
2282      * <p>After service discovery request is added, you can initiate service discovery by
2283      * {@link #discoverServices}.
2284      *
2285      * <p>The added service requests can be cleared with calls to
2286      * {@link #removeServiceRequest(Channel, WifiP2pServiceRequest, ActionListener)} or
2287      * {@link #clearServiceRequests(Channel, ActionListener)}.
2288      *
2289      * @param channel is the channel created at {@link #initialize}
2290      * @param req is the service discovery request.
2291      * @param listener for callbacks on success or failure. Can be null.
2292      */
addServiceRequest(Channel channel, WifiP2pServiceRequest req, ActionListener listener)2293     public void addServiceRequest(Channel channel,
2294             WifiP2pServiceRequest req, ActionListener listener) {
2295         checkChannel(channel);
2296         checkServiceRequest(req);
2297         channel.mAsyncChannel.sendMessage(ADD_SERVICE_REQUEST, 0,
2298                 channel.putListener(listener), req);
2299     }
2300 
2301     /**
2302      * Remove a specified service discovery request added with {@link #addServiceRequest}
2303      *
2304      * <p> The function call immediately returns after sending a request to remove service
2305      * discovery request to the framework. The application is notified of a success or failure to
2306      * add service through listener callbacks {@link ActionListener#onSuccess} or
2307      * {@link ActionListener#onFailure}.
2308      *
2309      * @param channel is the channel created at {@link #initialize}
2310      * @param req is the service discovery request.
2311      * @param listener for callbacks on success or failure. Can be null.
2312      */
removeServiceRequest(Channel channel, WifiP2pServiceRequest req, ActionListener listener)2313     public void removeServiceRequest(Channel channel, WifiP2pServiceRequest req,
2314             ActionListener listener) {
2315         checkChannel(channel);
2316         checkServiceRequest(req);
2317         channel.mAsyncChannel.sendMessage(REMOVE_SERVICE_REQUEST, 0,
2318                 channel.putListener(listener), req);
2319     }
2320 
2321     /**
2322      * Clear all registered service discovery requests.
2323      *
2324      * <p> The function call immediately returns after sending a request to clear all
2325      * service discovery requests to the framework. The application is notified of a success
2326      * or failure to add service through listener callbacks {@link ActionListener#onSuccess} or
2327      * {@link ActionListener#onFailure}.
2328      *
2329      * @param channel is the channel created at {@link #initialize}
2330      * @param listener for callbacks on success or failure. Can be null.
2331      */
clearServiceRequests(Channel channel, ActionListener listener)2332     public void clearServiceRequests(Channel channel, ActionListener listener) {
2333         checkChannel(channel);
2334         channel.mAsyncChannel.sendMessage(CLEAR_SERVICE_REQUESTS,
2335                 0, channel.putListener(listener));
2336     }
2337 
2338     /**
2339      * Request the current list of peers.
2340      * <p>
2341      * If targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later, the application must
2342      * have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
2343      * android:usesPermissionFlags="neverForLocation". If the application does not declare
2344      * android:usesPermissionFlags="neverForLocation", then it must also have
2345      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
2346      *
2347      * If targeting an earlier release than {@link android.os.Build.VERSION_CODES#TIRAMISU}, the
2348      * application must have {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
2349      *
2350      * @param channel is the channel created at {@link #initialize}
2351      * @param listener for callback when peer list is available. Can be null.
2352      */
2353     @RequiresPermission(allOf = {
2354             android.Manifest.permission.NEARBY_WIFI_DEVICES,
2355             android.Manifest.permission.ACCESS_FINE_LOCATION
2356             }, conditional = true)
requestPeers(Channel channel, PeerListListener listener)2357     public void requestPeers(Channel channel, PeerListListener listener) {
2358         checkChannel(channel);
2359         Bundle extras = prepareExtrasBundle(channel);
2360         channel.mAsyncChannel.sendMessage(prepareMessage(REQUEST_PEERS, 0,
2361                 channel.putListener(listener), extras, channel.mContext));
2362     }
2363 
2364     /**
2365      * Request device connection info.
2366      *
2367      * @param channel is the channel created at {@link #initialize}
2368      * @param listener for callback when connection info is available. Can be null.
2369      */
requestConnectionInfo(Channel channel, ConnectionInfoListener listener)2370     public void requestConnectionInfo(Channel channel, ConnectionInfoListener listener) {
2371         checkChannel(channel);
2372         channel.mAsyncChannel.sendMessage(
2373                 REQUEST_CONNECTION_INFO, 0, channel.putListener(listener));
2374     }
2375 
2376     /**
2377      * Request p2p group info.
2378      * <p>
2379      * If targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later, the application must
2380      * have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
2381      * android:usesPermissionFlags="neverForLocation". If the application does not declare
2382      * android:usesPermissionFlags="neverForLocation", then it must also have
2383      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
2384      *
2385      * If targeting an earlier release than {@link android.os.Build.VERSION_CODES#TIRAMISU}, the
2386      * application must have {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
2387      *
2388      * @param channel is the channel created at {@link #initialize}
2389      * @param listener for callback when group info is available. Can be null.
2390      */
2391     @RequiresPermission(allOf = {
2392             android.Manifest.permission.NEARBY_WIFI_DEVICES,
2393             android.Manifest.permission.ACCESS_FINE_LOCATION
2394             }, conditional = true)
requestGroupInfo(Channel channel, GroupInfoListener listener)2395     public void requestGroupInfo(Channel channel, GroupInfoListener listener) {
2396         checkChannel(channel);
2397         Bundle extras = prepareExtrasBundle(channel);
2398         channel.mAsyncChannel.sendMessage(prepareMessage(REQUEST_GROUP_INFO, 0,
2399                 channel.putListener(listener), extras, channel.mContext));
2400     }
2401 
2402     /**
2403      * Set p2p device name.
2404      *
2405      * @param channel is the channel created at {@link #initialize}
2406      * @param listener for callback when group info is available. Can be null.
2407      *
2408      * @hide
2409      */
2410     @SystemApi
2411     @RequiresPermission(anyOf = {
2412             android.Manifest.permission.NETWORK_SETTINGS,
2413             android.Manifest.permission.NETWORK_STACK,
2414             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
2415     })
setDeviceName(@onNull Channel channel, @NonNull String devName, @Nullable ActionListener listener)2416     public void setDeviceName(@NonNull Channel channel, @NonNull String devName,
2417             @Nullable ActionListener listener) {
2418         checkChannel(channel);
2419         WifiP2pDevice d = new WifiP2pDevice();
2420         d.deviceName = devName;
2421         channel.mAsyncChannel.sendMessage(SET_DEVICE_NAME, 0, channel.putListener(listener), d);
2422     }
2423 
2424     /**
2425      * Set Wifi Display information.
2426      *
2427      * @param channel is the channel created at {@link #initialize}
2428      * @param wfdInfo the Wifi Display information to set
2429      * @param listener for callbacks on success or failure. Can be null.
2430      */
2431     @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
setWfdInfo(@onNull Channel channel, @NonNull WifiP2pWfdInfo wfdInfo, @Nullable ActionListener listener)2432     public void setWfdInfo(@NonNull Channel channel, @NonNull WifiP2pWfdInfo wfdInfo,
2433             @Nullable ActionListener listener) {
2434         setWFDInfo(channel, wfdInfo, listener);
2435     }
2436 
2437     /** @hide */
2438     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
2439     @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
setWFDInfo(@onNull Channel channel, @NonNull WifiP2pWfdInfo wfdInfo, @Nullable ActionListener listener)2440     public void setWFDInfo(@NonNull Channel channel, @NonNull WifiP2pWfdInfo wfdInfo,
2441             @Nullable ActionListener listener) {
2442         checkChannel(channel);
2443         try {
2444             mService.checkConfigureWifiDisplayPermission();
2445         } catch (RemoteException e) {
2446             e.rethrowFromSystemServer();
2447         }
2448         channel.mAsyncChannel.sendMessage(SET_WFD_INFO, 0, channel.putListener(listener), wfdInfo);
2449     }
2450 
2451     /**
2452      * Remove the client with the MAC address from the group.
2453      *
2454      * <p> The function call immediately returns after sending a client removal request
2455      * to the framework. The application is notified of a success or failure to initiate
2456      * client removal through listener callbacks {@link ActionListener#onSuccess} or
2457      * {@link ActionListener#onFailure}.
2458      *
2459      * <p> The callbacks are triggered on the thread specified when initializing the
2460      * {@code channel}, see {@link #initialize}.
2461      * <p>
2462      * Use {@link #isGroupClientRemovalSupported()} to determine whether the device supports
2463      * this feature. If {@link #isGroupClientRemovalSupported()} return {@code false} then this
2464      * method will throw {@link UnsupportedOperationException}.
2465      *
2466      * @param channel is the channel created at {@link #initialize}
2467      * @param peerAddress MAC address of the client.
2468      * @param listener for callbacks on success or failure. Can be null.
2469      */
2470     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
removeClient(@onNull Channel channel, @NonNull MacAddress peerAddress, @Nullable ActionListener listener)2471     public void removeClient(@NonNull Channel channel, @NonNull MacAddress peerAddress,
2472             @Nullable ActionListener listener) {
2473         if (!isGroupClientRemovalSupported()) {
2474             throw new UnsupportedOperationException();
2475         }
2476         checkChannel(channel);
2477         channel.mAsyncChannel.sendMessage(
2478                 REMOVE_CLIENT, 0, channel.putListener(listener), peerAddress);
2479     }
2480 
2481 
2482     /**
2483      * Delete a stored persistent group from the system settings.
2484      *
2485      * <p> The function call immediately returns after sending a persistent group removal request
2486      * to the framework. The application is notified of a success or failure to initiate
2487      * group removal through listener callbacks {@link ActionListener#onSuccess} or
2488      * {@link ActionListener#onFailure}.
2489      *
2490      * <p>The persistent p2p group list stored in the system can be obtained by
2491      * {@link #requestPersistentGroupInfo(Channel, PersistentGroupInfoListener)} and
2492      *  a network id can be obtained by {@link WifiP2pGroup#getNetworkId()}.
2493      *
2494      * @param channel is the channel created at {@link #initialize}
2495      * @param netId the network id of the p2p group.
2496      * @param listener for callbacks on success or failure. Can be null.
2497      *
2498      * @hide
2499      */
2500     @SystemApi
2501     @RequiresPermission(anyOf = {
2502             android.Manifest.permission.NETWORK_SETTINGS,
2503             android.Manifest.permission.NETWORK_STACK,
2504             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
2505     })
deletePersistentGroup(@onNull Channel channel, int netId, @Nullable ActionListener listener)2506     public void deletePersistentGroup(@NonNull Channel channel, int netId,
2507             @Nullable ActionListener listener) {
2508         checkChannel(channel);
2509         channel.mAsyncChannel.sendMessage(
2510                 DELETE_PERSISTENT_GROUP, netId, channel.putListener(listener));
2511     }
2512 
2513     /**
2514      * Request a list of all the persistent p2p groups stored in system.
2515      *
2516      * <p>The caller must have one of {@link android.Manifest.permission.NETWORK_SETTINGS},
2517      * {@link android.Manifest.permission.NETWORK_STACK}, and
2518      * {@link android.Manifest.permission.READ_WIFI_CREDENTIAL}.
2519      *
2520      * <p>If targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later,
2521      * the application must have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
2522      * android:usesPermissionFlags="neverForLocation". If the application does not declare
2523      * android:usesPermissionFlags="neverForLocation", then it must also have
2524      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
2525      *
2526      * @param channel is the channel created at {@link #initialize}
2527      * @param listener for callback when persistent group info list is available. Can be null.
2528      *
2529      * @hide
2530      */
2531     @SystemApi
2532     @RequiresPermission(allOf = {
2533             android.Manifest.permission.NETWORK_SETTINGS,
2534             android.Manifest.permission.NETWORK_STACK,
2535             android.Manifest.permission.READ_WIFI_CREDENTIAL,
2536             android.Manifest.permission.NEARBY_WIFI_DEVICES,
2537             android.Manifest.permission.ACCESS_FINE_LOCATION}, conditional = true)
requestPersistentGroupInfo(@onNull Channel channel, @Nullable PersistentGroupInfoListener listener)2538     public void requestPersistentGroupInfo(@NonNull Channel channel,
2539             @Nullable PersistentGroupInfoListener listener) {
2540         checkChannel(channel);
2541         Bundle extras = prepareExtrasBundle(channel);
2542         channel.mAsyncChannel.sendMessage(prepareMessage(REQUEST_PERSISTENT_GROUP_INFO, 0,
2543                 channel.putListener(listener), extras, channel.mContext));
2544     }
2545 
2546     /** @hide */
2547     @Retention(RetentionPolicy.SOURCE)
2548     @IntDef(prefix = {"MIRACAST_"}, value = {
2549             MIRACAST_DISABLED,
2550             MIRACAST_SOURCE,
2551             MIRACAST_SINK})
2552     public @interface MiracastMode {}
2553 
2554     /**
2555      * Miracast is disabled.
2556      * @hide
2557      */
2558     @SystemApi
2559     public static final int MIRACAST_DISABLED = 0;
2560     /**
2561      * Device acts as a Miracast source.
2562      * @hide
2563      */
2564     @SystemApi
2565     public static final int MIRACAST_SOURCE   = 1;
2566     /**
2567      * Device acts as a Miracast sink.
2568      * @hide
2569      */
2570     @SystemApi
2571     public static final int MIRACAST_SINK     = 2;
2572 
2573     /**
2574      * Accept the incoming request.
2575      *
2576      * Used in {@link #setConnectionRequestResult(Channel, MacAddress, int, ActionListener)}.
2577      */
2578     public static final int CONNECTION_REQUEST_ACCEPT = 0;
2579     /**
2580      * Reject the incoming request.
2581      *
2582      * Used in {@link #setConnectionRequestResult(Channel, MacAddress, int, ActionListener)}.
2583      */
2584     public static final int CONNECTION_REQUEST_REJECT = 1;
2585     /**
2586      * Defer the decision back to the Wi-Fi service (which will display a dialog to the user).
2587      *
2588      * Used in {@link #setConnectionRequestResult(Channel, MacAddress, int, ActionListener)}.
2589      */
2590     public static final int CONNECTION_REQUEST_DEFER_TO_SERVICE = 2;
2591     /**
2592      * Defer the PIN display to the Wi-Fi service (which will display a dialog to the user).
2593      *
2594      * Used in {@link #setConnectionRequestResult(Channel, MacAddress, int, ActionListener)}.
2595      */
2596     public static final int CONNECTION_REQUEST_DEFER_SHOW_PIN_TO_SERVICE = 3;
2597     /** @hide */
2598     @IntDef(prefix = {"CONNECTION_REQUEST_"}, value = {
2599         CONNECTION_REQUEST_ACCEPT,
2600         CONNECTION_REQUEST_REJECT,
2601         CONNECTION_REQUEST_DEFER_TO_SERVICE,
2602         CONNECTION_REQUEST_DEFER_SHOW_PIN_TO_SERVICE})
2603     @Retention(RetentionPolicy.SOURCE)
2604     public @interface ConnectionRequestResponse {
2605     }
2606 
2607     /**
2608      * This is used to provide information to drivers to optimize performance depending
2609      * on the current mode of operation.
2610      * {@link #MIRACAST_DISABLED} - disabled
2611      * {@link #MIRACAST_SOURCE} - source operation
2612      * {@link #MIRACAST_SINK} - sink operation
2613      *
2614      * As an example, the driver could reduce the channel dwell time during scanning
2615      * when acting as a source or sink to minimize impact on Miracast.
2616      *
2617      * @param mode mode of operation. One of {@link #MIRACAST_DISABLED}, {@link #MIRACAST_SOURCE},
2618      * or {@link #MIRACAST_SINK}
2619      *
2620      * @hide
2621      */
2622     @SystemApi
2623     @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
setMiracastMode(@iracastMode int mode)2624     public void setMiracastMode(@MiracastMode int mode) {
2625         try {
2626             mService.setMiracastMode(mode);
2627         } catch (RemoteException e) {
2628             throw e.rethrowFromSystemServer();
2629         }
2630     }
2631 
getMessenger(@onNull Binder binder, @Nullable String packageName, @NonNull Bundle extras)2632     private Messenger getMessenger(@NonNull Binder binder, @Nullable String packageName,
2633             @NonNull Bundle extras) {
2634         try {
2635             return mService.getMessenger(binder, packageName, extras);
2636         } catch (RemoteException e) {
2637             throw e.rethrowFromSystemServer();
2638         }
2639     }
2640 
2641     /**
2642      * Get a reference to P2pStateMachine handler. This is used to establish
2643      * a priveleged AsyncChannel communication with WifiP2pService.
2644      *
2645      * @return Messenger pointing to the WifiP2pService handler
2646      * @hide
2647      */
getP2pStateMachineMessenger()2648     public Messenger getP2pStateMachineMessenger() {
2649         try {
2650             return mService.getP2pStateMachineMessenger();
2651         } catch (RemoteException e) {
2652             throw e.rethrowFromSystemServer();
2653         }
2654     }
2655 
getSupportedFeatures()2656     private long getSupportedFeatures() {
2657         try {
2658             return mService.getSupportedFeatures();
2659         } catch (RemoteException e) {
2660             throw e.rethrowFromSystemServer();
2661         }
2662     }
2663 
isFeatureSupported(long feature)2664     private boolean isFeatureSupported(long feature) {
2665         return (getSupportedFeatures() & feature) == feature;
2666     }
2667 
2668     /**
2669      * Check if this device supports setting vendor elements.
2670      *
2671      * Gates whether the
2672      * {@link #setVendorElements(Channel, List, ActionListener)}
2673      * method is functional on this device.
2674      *
2675      * @return {@code true} if supported, {@code false} otherwise.
2676      */
isSetVendorElementsSupported()2677     public boolean isSetVendorElementsSupported() {
2678         return isFeatureSupported(FEATURE_SET_VENDOR_ELEMENTS);
2679     }
2680 
2681     /**
2682      * Check if this device supports discovery limited to a specific frequency or
2683      * the social channels.
2684      *
2685      * Gates whether
2686      * {@link #discoverPeersOnSpecificFrequency(Channel, int, ActionListener)} and
2687      * {@link #discoverPeersOnSocialChannels(Channel, ActionListener)}
2688      * methods are functional on this device.
2689      *
2690      * @return {@code true} if supported, {@code false} otherwise.
2691      */
isChannelConstrainedDiscoverySupported()2692     public boolean isChannelConstrainedDiscoverySupported() {
2693         return isFeatureSupported(FEATURE_FLEXIBLE_DISCOVERY);
2694     }
2695 
2696     /**
2697      * Check if this device supports removing clients from a group.
2698      *
2699      * Gates whether the
2700      * {@link #removeClient(Channel, MacAddress, ActionListener)}
2701      * method is functional on this device.
2702      * @return {@code true} if supported, {@code false} otherwise.
2703      */
isGroupClientRemovalSupported()2704     public boolean isGroupClientRemovalSupported() {
2705         return isFeatureSupported(FEATURE_GROUP_CLIENT_REMOVAL);
2706     }
2707 
2708     /**
2709      * Checks whether this device, while being a group client, can discover and deliver the group
2710      * owner's IPv6 link-local address.
2711      *
2712      * <p>If this method returns {@code true} and
2713      * {@link #connect(Channel, WifiP2pConfig, ActionListener)} method is called with
2714      * {@link WifiP2pConfig} having
2715      * {@link WifiP2pConfig#GROUP_CLIENT_IP_PROVISIONING_MODE_IPV6_LINK_LOCAL} as the group client
2716      * IP provisioning mode, then the group owner's IPv6 link-local address will be delivered in the
2717      * group client via {@link #WIFI_P2P_CONNECTION_CHANGED_ACTION} broadcast intent (i.e, group
2718      * owner address in {@link #EXTRA_WIFI_P2P_INFO}).
2719      * If this method returns {@code false}, then IPv6 link-local addresses can still be used, but
2720      * it is the responsibility of the caller to discover that address in other ways, e.g. using
2721      * out-of-band communication.
2722      *
2723      * @return {@code true} if supported, {@code false} otherwise.
2724      */
isGroupOwnerIPv6LinkLocalAddressProvided()2725     public boolean isGroupOwnerIPv6LinkLocalAddressProvided() {
2726         return SdkLevel.isAtLeastT()
2727                 && isFeatureSupported(FEATURE_GROUP_OWNER_IPV6_LINK_LOCAL_ADDRESS_PROVIDED);
2728     }
2729 
2730     /**
2731      * Get a handover request message for use in WFA NFC Handover transfer.
2732      * @hide
2733      */
getNfcHandoverRequest(Channel c, HandoverMessageListener listener)2734     public void getNfcHandoverRequest(Channel c, HandoverMessageListener listener) {
2735         checkChannel(c);
2736         c.mAsyncChannel.sendMessage(GET_HANDOVER_REQUEST, 0, c.putListener(listener));
2737     }
2738 
2739 
2740     /**
2741      * Get a handover select message for use in WFA NFC Handover transfer.
2742      * @hide
2743      */
getNfcHandoverSelect(Channel c, HandoverMessageListener listener)2744     public void getNfcHandoverSelect(Channel c, HandoverMessageListener listener) {
2745         checkChannel(c);
2746         c.mAsyncChannel.sendMessage(GET_HANDOVER_SELECT, 0, c.putListener(listener));
2747     }
2748 
2749     /**
2750      * @hide
2751      */
initiatorReportNfcHandover(Channel c, String handoverSelect, ActionListener listener)2752     public void initiatorReportNfcHandover(Channel c, String handoverSelect,
2753                                               ActionListener listener) {
2754         checkChannel(c);
2755         Bundle bundle = new Bundle();
2756         bundle.putString(EXTRA_HANDOVER_MESSAGE, handoverSelect);
2757         c.mAsyncChannel.sendMessage(INITIATOR_REPORT_NFC_HANDOVER, 0,
2758                 c.putListener(listener), bundle);
2759     }
2760 
2761 
2762     /**
2763      * @hide
2764      */
responderReportNfcHandover(Channel c, String handoverRequest, ActionListener listener)2765     public void responderReportNfcHandover(Channel c, String handoverRequest,
2766                                               ActionListener listener) {
2767         checkChannel(c);
2768         Bundle bundle = new Bundle();
2769         bundle.putString(EXTRA_HANDOVER_MESSAGE, handoverRequest);
2770         c.mAsyncChannel.sendMessage(RESPONDER_REPORT_NFC_HANDOVER, 0,
2771                 c.putListener(listener), bundle);
2772     }
2773 
2774     /**
2775      * Removes all saved p2p groups.
2776      *
2777      * @param c is the channel created at {@link #initialize}.
2778      * @param listener for callback on success or failure. Can be null.
2779      *
2780      * @hide
2781      */
2782     @SystemApi
2783     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
factoryReset(@onNull Channel c, @Nullable ActionListener listener)2784     public void factoryReset(@NonNull Channel c, @Nullable ActionListener listener) {
2785         checkChannel(c);
2786         c.mAsyncChannel.sendMessage(FACTORY_RESET, 0, c.putListener(listener));
2787     }
2788 
2789     /**
2790      * Request saved WifiP2pConfig which used for an ongoing peer connection
2791      *
2792      * @param c is the channel created at {@link #initialize}
2793      * @param listener for callback when ongoing peer config updated. Can't be null.
2794      *
2795      * @hide
2796      */
2797     @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
requestOngoingPeerConfig(@onNull Channel c, @NonNull OngoingPeerInfoListener listener)2798     public void requestOngoingPeerConfig(@NonNull Channel c,
2799             @NonNull OngoingPeerInfoListener listener) {
2800         checkChannel(c);
2801         c.mAsyncChannel.sendMessage(REQUEST_ONGOING_PEER_CONFIG,
2802                 Binder.getCallingUid(), c.putListener(listener));
2803     }
2804 
2805      /**
2806      * Set saved WifiP2pConfig which used for an ongoing peer connection
2807      *
2808      * @param c is the channel created at {@link #initialize}
2809      * @param config used for change an ongoing peer connection
2810      * @param listener for callback when ongoing peer config updated. Can be null.
2811      *
2812      * @hide
2813      */
2814     @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
setOngoingPeerConfig(@onNull Channel c, @NonNull WifiP2pConfig config, @Nullable ActionListener listener)2815     public void setOngoingPeerConfig(@NonNull Channel c, @NonNull WifiP2pConfig config,
2816             @Nullable ActionListener listener) {
2817         checkChannel(c);
2818         checkP2pConfig(config);
2819         c.mAsyncChannel.sendMessage(SET_ONGOING_PEER_CONFIG, 0,
2820                 c.putListener(listener), config);
2821     }
2822 
2823     /**
2824      * Request p2p enabled state.
2825      *
2826      * <p> This state indicates whether Wi-Fi p2p is enabled or disabled.
2827      * The valid value is one of {@link #WIFI_P2P_STATE_DISABLED} or
2828      * {@link #WIFI_P2P_STATE_ENABLED}. The state is returned using the
2829      * {@link P2pStateListener} listener.
2830      *
2831      * <p> This state is also included in the {@link #WIFI_P2P_STATE_CHANGED_ACTION}
2832      * broadcast event with extra {@link #EXTRA_WIFI_STATE}.
2833      *
2834      * @param c is the channel created at {@link #initialize}.
2835      * @param listener for callback when p2p state is available.
2836      */
requestP2pState(@onNull Channel c, @NonNull P2pStateListener listener)2837     public void requestP2pState(@NonNull Channel c,
2838             @NonNull P2pStateListener listener) {
2839         checkChannel(c);
2840         if (listener == null) throw new IllegalArgumentException("This listener cannot be null.");
2841         c.mAsyncChannel.sendMessage(REQUEST_P2P_STATE, 0, c.putListener(listener));
2842     }
2843 
2844     /**
2845      * Request p2p discovery state.
2846      *
2847      * <p> This state indicates whether p2p discovery has started or stopped.
2848      * The valid value is one of {@link #WIFI_P2P_DISCOVERY_STARTED} or
2849      * {@link #WIFI_P2P_DISCOVERY_STOPPED}. The state is returned using the
2850      * {@link DiscoveryStateListener} listener.
2851      *
2852      * <p> This state is also included in the {@link #WIFI_P2P_DISCOVERY_CHANGED_ACTION}
2853      * broadcast event with extra {@link #EXTRA_DISCOVERY_STATE}.
2854      *
2855      * @param c is the channel created at {@link #initialize}.
2856      * @param listener for callback when discovery state is available.
2857      */
requestDiscoveryState(@onNull Channel c, @NonNull DiscoveryStateListener listener)2858     public void requestDiscoveryState(@NonNull Channel c,
2859             @NonNull DiscoveryStateListener listener) {
2860         checkChannel(c);
2861         if (listener == null) throw new IllegalArgumentException("This listener cannot be null.");
2862         c.mAsyncChannel.sendMessage(REQUEST_DISCOVERY_STATE, 0, c.putListener(listener));
2863     }
2864 
2865     /**
2866      * Get p2p listen state.
2867      *
2868      * <p> This state indicates whether p2p listen has started or stopped.
2869      * The valid value is one of {@link #WIFI_P2P_LISTEN_STOPPED} or
2870      * {@link #WIFI_P2P_LISTEN_STARTED}.
2871      *
2872      * <p> This state is also included in the {@link #ACTION_WIFI_P2P_LISTEN_STATE_CHANGED}
2873      * broadcast event with extra {@link #EXTRA_LISTEN_STATE}.
2874      *
2875      * <p>
2876      * If targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later, the application must
2877      * have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
2878      * android:usesPermissionFlags="neverForLocation". If the application does not declare
2879      * android:usesPermissionFlags="neverForLocation", then it must also have
2880      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
2881      *
2882      * If targeting an earlier release than {@link android.os.Build.VERSION_CODES#TIRAMISU}, the
2883      * application must have {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
2884      *
2885      * @param c               It is the channel created at {@link #initialize}.
2886      * @param executor        The executor on which callback will be invoked.
2887      * @param resultsCallback A callback that will return listen state
2888      *                        {@link #WIFI_P2P_LISTEN_STOPPED} or {@link #WIFI_P2P_LISTEN_STARTED}
2889      */
2890     @RequiresPermission(allOf = {
2891             android.Manifest.permission.NEARBY_WIFI_DEVICES,
2892             android.Manifest.permission.ACCESS_FINE_LOCATION
2893             }, conditional = true)
getListenState(@onNull Channel c, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)2894     public void getListenState(@NonNull Channel c, @NonNull @CallbackExecutor Executor executor,
2895             @NonNull Consumer<Integer> resultsCallback) {
2896         Objects.requireNonNull(c, "channel cannot be null and needs to be initialized)");
2897         Objects.requireNonNull(executor, "executor cannot be null");
2898         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
2899         Bundle extras = prepareExtrasBundle(c);
2900         c.mAsyncChannel.sendMessage(prepareMessage(GET_LISTEN_STATE, 0,
2901                 c.putListener(new ListenStateListener() {
2902                     @Override
2903                     public void onListenStateAvailable(int state) {
2904                         Binder.clearCallingIdentity();
2905                         executor.execute(() -> {
2906                             resultsCallback.accept(state);
2907                         });
2908                     }
2909                 }), extras, c.mContext));
2910     }
2911 
2912     /**
2913      * Request network info.
2914      *
2915      * <p> This method provides the network info in the form of a {@link android.net.NetworkInfo}.
2916      * {@link android.net.NetworkInfo#isAvailable()} indicates the p2p availability and
2917      * {@link android.net.NetworkInfo#getDetailedState()} reports the current fine-grained state
2918      * of the network. This {@link android.net.NetworkInfo} is returned using the
2919      * {@link NetworkInfoListener} listener.
2920      *
2921      * <p> This information is also included in the {@link #WIFI_P2P_CONNECTION_CHANGED_ACTION}
2922      * broadcast event with extra {@link #EXTRA_NETWORK_INFO}.
2923      *
2924      * @param c is the channel created at {@link #initialize}.
2925      * @param listener for callback when network info is available.
2926      */
requestNetworkInfo(@onNull Channel c, @NonNull NetworkInfoListener listener)2927     public void requestNetworkInfo(@NonNull Channel c,
2928             @NonNull NetworkInfoListener listener) {
2929         checkChannel(c);
2930         if (listener == null) throw new IllegalArgumentException("This listener cannot be null.");
2931         c.mAsyncChannel.sendMessage(REQUEST_NETWORK_INFO, 0, c.putListener(listener));
2932     }
2933 
2934     /**
2935      * Request Device Info
2936      *
2937      * <p> This method provides the device info
2938      * in the form of a {@link android.net.wifi.p2p.WifiP2pDevice}.
2939      * Valid {@link android.net.wifi.p2p.WifiP2pDevice} is returned when p2p is enabled.
2940      * To get information notifications on P2P getting enabled refers
2941      * {@link #WIFI_P2P_STATE_ENABLED}.
2942      *
2943      * <p> This {@link android.net.wifi.p2p.WifiP2pDevice} is returned using the
2944      * {@link DeviceInfoListener} listener.
2945      *
2946      * <p> {@link android.net.wifi.p2p.WifiP2pDevice#deviceAddress} is only available if the caller
2947      * holds the {@code android.Manifest.permission#LOCAL_MAC_ADDRESS} permission, and holds the
2948      * anonymized MAC address (02:00:00:00:00:00) otherwise.
2949      *
2950      * <p> This information is also included in the {@link #WIFI_P2P_THIS_DEVICE_CHANGED_ACTION}
2951      * broadcast event with extra {@link #EXTRA_WIFI_P2P_DEVICE}.
2952      * <p>
2953      * If targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later, the application must
2954      * have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
2955      * android:usesPermissionFlags="neverForLocation". If the application does not declare
2956      * android:usesPermissionFlags="neverForLocation", then it must also have
2957      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
2958      *
2959      * If targeting an earlier release than {@link android.os.Build.VERSION_CODES#TIRAMISU}, the
2960      * application must have {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
2961      *
2962      * @param c is the channel created at {@link #initialize(Context, Looper, ChannelListener)}.
2963      * @param listener for callback when network info is available.
2964      */
2965     @RequiresPermission(allOf = {
2966             android.Manifest.permission.NEARBY_WIFI_DEVICES,
2967             android.Manifest.permission.ACCESS_FINE_LOCATION
2968             }, conditional = true)
requestDeviceInfo(@onNull Channel c, @NonNull DeviceInfoListener listener)2969     public void requestDeviceInfo(@NonNull Channel c, @NonNull DeviceInfoListener listener) {
2970         checkChannel(c);
2971         if (listener == null) throw new IllegalArgumentException("This listener cannot be null.");
2972 
2973         Bundle extras = prepareExtrasBundle(c);
2974         c.mAsyncChannel.sendMessage(prepareMessage(REQUEST_DEVICE_INFO, 0,
2975                 c.putListener(listener), extras, c.mContext));
2976     }
2977 
2978     /**
2979      * Set the external approver for a specific peer.
2980      *
2981      * This API associates a specific peer with an approver. When an incoming request is received
2982      * from a peer, an authorization request is routed to the attached approver. The approver then
2983      * calls {@link #setConnectionRequestResult(Channel, MacAddress, int, ActionListener)} to send
2984      * the result to the WiFi service. A specific peer (identified by its {@code MacAddress}) can
2985      * only be attached to a single approver. The previous approver will be detached once a new
2986      * approver is attached. The approver will also be detached automatically when the channel is
2987      * closed.
2988      * <p>
2989      * When an approver is attached, {@link ExternalApproverRequestListener#onAttached(MacAddress)}
2990      * is called. When an approver is detached,
2991      * {@link ExternalApproverRequestListener#onDetached(MacAddress, int)} is called.
2992      * When an incoming request is received,
2993      * {@link ExternalApproverRequestListener#onConnectionRequested(int, WifiP2pConfig, WifiP2pDevice)}
2994      * is called. When a WPS PIN is generated,
2995      * {@link ExternalApproverRequestListener#onPinGenerated(MacAddress, String)} is called.
2996      * <p>
2997      * The application must have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
2998      * android:usesPermissionFlags="neverForLocation". If the application does not declare
2999      * android:usesPermissionFlags="neverForLocation", then it must also have
3000      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
3001      *
3002      * @param c is the channel created at {@link #initialize(Context, Looper, ChannelListener)}.
3003      * @param deviceAddress the peer which is bound to the external approver.
3004      * @param listener for callback when the framework needs to notify the external approver.
3005      */
3006     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION)
addExternalApprover(@onNull Channel c, @NonNull MacAddress deviceAddress, @NonNull ExternalApproverRequestListener listener)3007     public void addExternalApprover(@NonNull Channel c, @NonNull MacAddress deviceAddress,
3008             @NonNull ExternalApproverRequestListener listener) {
3009         checkChannel(c);
3010         if (listener == null) throw new IllegalArgumentException("This listener cannot be null.");
3011         if (null == deviceAddress) {
3012             throw new IllegalArgumentException("deviceAddress cannot be empty");
3013         }
3014 
3015         Bundle extras = prepareExtrasBundle(c);
3016         extras.putParcelable(EXTRA_PARAM_KEY_PEER_ADDRESS, deviceAddress);
3017         c.mAsyncChannel.sendMessage(prepareMessage(ADD_EXTERNAL_APPROVER, 0,
3018                 c.putListener(listener), extras, c.mContext));
3019     }
3020 
3021     /**
3022      * Remove the external approver for a specific peer.
3023      *
3024      * The application must have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
3025      * android:usesPermissionFlags="neverForLocation". If the application does not declare
3026      * android:usesPermissionFlags="neverForLocation", then it must also have
3027      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
3028      *
3029      * @param c is the channel created at {@link #initialize(Context, Looper, ChannelListener)}.
3030      * @param deviceAddress the peer which is bound to the external approver.
3031      * @param listener for callback on success or failure.
3032      */
3033     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION)
removeExternalApprover(@onNull Channel c, @NonNull MacAddress deviceAddress, @Nullable ActionListener listener)3034     public void removeExternalApprover(@NonNull Channel c, @NonNull MacAddress deviceAddress,
3035             @Nullable ActionListener listener) {
3036         checkChannel(c);
3037         if (null == deviceAddress) {
3038             throw new IllegalArgumentException("deviceAddress cannot be empty");
3039         }
3040 
3041         Bundle extras = prepareExtrasBundle(c);
3042         extras.putParcelable(EXTRA_PARAM_KEY_PEER_ADDRESS, deviceAddress);
3043         c.mAsyncChannel.sendMessage(prepareMessage(REMOVE_EXTERNAL_APPROVER, 0,
3044                 c.putListener(listener), extras, c.mContext));
3045     }
3046 
3047     /**
3048      * Set the result for the incoming request from a specific peer.
3049      *
3050      * The application must have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
3051      * android:usesPermissionFlags="neverForLocation". If the application does not declare
3052      * android:usesPermissionFlags="neverForLocation", then it must also have
3053      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
3054      *
3055      * @param c is the channel created at {@link #initialize(Context, Looper, ChannelListener)}.
3056      * @param deviceAddress the peer which is bound to the external approver.
3057      * @param result the response for the incoming request.
3058      * @param listener for callback on success or failure.
3059      */
3060     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION)
setConnectionRequestResult(@onNull Channel c, @NonNull MacAddress deviceAddress, @ConnectionRequestResponse int result, @Nullable ActionListener listener)3061     public void setConnectionRequestResult(@NonNull Channel c, @NonNull MacAddress deviceAddress,
3062             @ConnectionRequestResponse int result, @Nullable ActionListener listener) {
3063         checkChannel(c);
3064         if (null == deviceAddress) {
3065             throw new IllegalArgumentException("deviceAddress cannot be empty");
3066         }
3067 
3068         Bundle extras = prepareExtrasBundle(c);
3069         extras.putParcelable(EXTRA_PARAM_KEY_PEER_ADDRESS, deviceAddress);
3070         c.mAsyncChannel.sendMessage(prepareMessage(SET_CONNECTION_REQUEST_RESULT,
3071                 result, c.putListener(listener), extras, c.mContext));
3072     }
3073 
3074     /**
3075      * Set the result with PIN for the incoming request from a specific peer.
3076      *
3077      * The application must have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
3078      * android:usesPermissionFlags="neverForLocation". If the application does not declare
3079      * android:usesPermissionFlags="neverForLocation", then it must also have
3080      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
3081      *
3082      * @param c is the channel created at {@link #initialize(Context, Looper, ChannelListener)}.
3083      * @param deviceAddress the peer which is bound to the external approver.
3084      * @param result the response for the incoming request.
3085      * @param pin the PIN for the incoming request.
3086      * @param listener for callback on success or failure.
3087      */
3088     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION)
setConnectionRequestResult(@onNull Channel c, @NonNull MacAddress deviceAddress, @ConnectionRequestResponse int result, @Nullable String pin, @Nullable ActionListener listener)3089     public void setConnectionRequestResult(@NonNull Channel c, @NonNull MacAddress deviceAddress,
3090             @ConnectionRequestResponse int result, @Nullable String pin,
3091             @Nullable ActionListener listener) {
3092         checkChannel(c);
3093         if (null == deviceAddress) {
3094             throw new IllegalArgumentException("deviceAddress cannot be empty");
3095         }
3096         if (result == CONNECTION_REQUEST_ACCEPT && TextUtils.isEmpty(pin)) {
3097             throw new IllegalArgumentException("PIN cannot be empty for accepting a request");
3098         }
3099 
3100         Bundle extras = prepareExtrasBundle(c);
3101         extras.putParcelable(EXTRA_PARAM_KEY_PEER_ADDRESS, deviceAddress);
3102         extras.putString(EXTRA_PARAM_KEY_WPS_PIN, pin);
3103         c.mAsyncChannel.sendMessage(prepareMessage(SET_CONNECTION_REQUEST_RESULT,
3104                 result, c.putListener(listener), extras, c.mContext));
3105     }
3106 
3107     /**
3108      * Set/Clear vendor specific information elements (VSIEs) to be published during
3109      * Wi-Fi Direct (P2P) discovery.
3110      *
3111      * Once {@link Channel#close()} is called, the vendor information elements will be cleared from
3112      * framework. The information element format is defined in the IEEE 802.11-2016 spec
3113      * Table 9-77.
3114      * <p>
3115      * To clear the previously set vendor elements, call this API with an empty List.
3116      * <p>
3117      * The maximum accumulated length of all VSIEs must be before the limit specified by
3118      * {@link #getP2pMaxAllowedVendorElementsLengthBytes()}.
3119      * <p>
3120      * To publish vendor elements, this API should be called before peer discovery API, ex.
3121      * {@link #discoverPeers(Channel, ActionListener)}.
3122      * <p>
3123      * Use {@link #isSetVendorElementsSupported()} to determine whether the device supports
3124      * this feature. If {@link #isSetVendorElementsSupported()} return {@code false} then
3125      * this method will throw {@link UnsupportedOperationException}.
3126      *
3127      * @param c is the channel created at {@link #initialize(Context, Looper, ChannelListener)}.
3128      * @param vendorElements application information as vendor-specific information elements.
3129      * @param listener for callback when network info is available.
3130      */
3131     @RequiresPermission(allOf = {
3132             android.Manifest.permission.NEARBY_WIFI_DEVICES,
3133             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
3134             })
setVendorElements(@onNull Channel c, @NonNull List<ScanResult.InformationElement> vendorElements, @Nullable ActionListener listener)3135     public void setVendorElements(@NonNull Channel c,
3136             @NonNull List<ScanResult.InformationElement> vendorElements,
3137             @Nullable ActionListener listener) {
3138         if (!isSetVendorElementsSupported()) {
3139             throw new UnsupportedOperationException();
3140         }
3141         checkChannel(c);
3142         int totalBytes = 0;
3143         for (ScanResult.InformationElement e : vendorElements) {
3144             if (e.id != ScanResult.InformationElement.EID_VSA) {
3145                 throw new IllegalArgumentException("received InformationElement which is not "
3146                         + "a Vendor Specific IE (VSIE). VSIEs have an ID = 221.");
3147             }
3148             // Length field is 1 byte.
3149             if (e.bytes == null || e.bytes.length > 0xff) {
3150                 throw new IllegalArgumentException("received InformationElement whose payload "
3151                         + "size is 0 or greater than 255.");
3152             }
3153             // The total bytes of an IE is EID (1 byte) + length (1 byte) + payload length.
3154             totalBytes += 2 + e.bytes.length;
3155             if (totalBytes > WIFI_P2P_VENDOR_ELEMENTS_MAXIMUM_LENGTH) {
3156                 throw new IllegalArgumentException("received InformationElement whose total "
3157                         + "size is greater than " + WIFI_P2P_VENDOR_ELEMENTS_MAXIMUM_LENGTH + ".");
3158             }
3159         }
3160         Bundle extras = prepareExtrasBundle(c);
3161         extras.putParcelableArrayList(EXTRA_PARAM_KEY_INFORMATION_ELEMENT_LIST,
3162                 new ArrayList<>(vendorElements));
3163         c.mAsyncChannel.sendMessage(prepareMessage(SET_VENDOR_ELEMENTS, 0,
3164                 c.putListener(listener), extras, c.mContext));
3165     }
3166 
3167     /**
3168      * Return the maximum total length (in bytes) of all Vendor specific information
3169      * elements (VSIEs) which can be set using the
3170      * {@link #setVendorElements(Channel, List, ActionListener)}.
3171      *
3172      * The length is calculated adding the payload length + 2 bytes for each VSIE
3173      * (2 bytes: 1 byte for type and 1 byte for length).
3174      */
getP2pMaxAllowedVendorElementsLengthBytes()3175     public static int getP2pMaxAllowedVendorElementsLengthBytes() {
3176         return WIFI_P2P_VENDOR_ELEMENTS_MAXIMUM_LENGTH;
3177     }
3178 }
3179