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