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