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