1 /* 2 * Copyright (C) 2016 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.aware; 18 19 import static android.Manifest.permission.ACCESS_FINE_LOCATION; 20 import static android.Manifest.permission.ACCESS_WIFI_STATE; 21 import static android.Manifest.permission.CHANGE_WIFI_STATE; 22 import static android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION; 23 import static android.Manifest.permission.NEARBY_WIFI_DEVICES; 24 import static android.Manifest.permission.OVERRIDE_WIFI_CONFIG; 25 import static android.net.wifi.ScanResult.WIFI_BAND_24_GHZ; 26 import static android.net.wifi.ScanResult.WIFI_BAND_5_GHZ; 27 28 import android.annotation.CallbackExecutor; 29 import android.annotation.FlaggedApi; 30 import android.annotation.IntDef; 31 import android.annotation.NonNull; 32 import android.annotation.Nullable; 33 import android.annotation.RequiresPermission; 34 import android.annotation.SdkConstant; 35 import android.annotation.SdkConstant.SdkConstantType; 36 import android.annotation.SystemApi; 37 import android.annotation.SystemService; 38 import android.content.Context; 39 import android.net.ConnectivityManager; 40 import android.net.MacAddress; 41 import android.net.NetworkRequest; 42 import android.net.NetworkSpecifier; 43 import android.net.wifi.IBooleanListener; 44 import android.net.wifi.IIntegerListener; 45 import android.net.wifi.IListListener; 46 import android.net.wifi.OuiKeyedData; 47 import android.net.wifi.WifiManager; 48 import android.net.wifi.rtt.RangingResult; 49 import android.net.wifi.util.HexEncoding; 50 import android.os.Binder; 51 import android.os.Build; 52 import android.os.Bundle; 53 import android.os.Handler; 54 import android.os.Looper; 55 import android.os.RemoteException; 56 import android.util.Log; 57 58 import androidx.annotation.RequiresApi; 59 60 import com.android.modules.utils.HandlerExecutor; 61 import com.android.modules.utils.build.SdkLevel; 62 import com.android.wifi.flags.Flags; 63 64 import java.lang.annotation.Retention; 65 import java.lang.annotation.RetentionPolicy; 66 import java.lang.ref.WeakReference; 67 import java.nio.BufferOverflowException; 68 import java.util.Collections; 69 import java.util.List; 70 import java.util.Objects; 71 import java.util.concurrent.Executor; 72 import java.util.function.Consumer; 73 74 /** 75 * This class provides the primary API for managing Wi-Fi Aware operations: 76 * discovery and peer-to-peer data connections. 77 * <p> 78 * The class provides access to: 79 * <ul> 80 * <li>Initialize a Aware cluster (peer-to-peer synchronization). Refer to 81 * {@link #attach(AttachCallback, Handler)}. 82 * <li>Create discovery sessions (publish or subscribe sessions). Refer to 83 * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback, Handler)} and 84 * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback, Handler)}. 85 * <li>Create a Aware network specifier to be used with 86 * {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)} 87 * to set-up a Aware connection with a peer. Refer to {@link WifiAwareNetworkSpecifier.Builder}. 88 * </ul> 89 * <p> 90 * Aware may not be usable when Wi-Fi is disabled (and other conditions). To validate that 91 * the functionality is available use the {@link #isAvailable()} function. To track 92 * changes in Aware usability register for the {@link #ACTION_WIFI_AWARE_STATE_CHANGED} 93 * broadcast. Note that this broadcast is not sticky - you should register for it and then 94 * check the above API to avoid a race condition. 95 * <p> 96 * An application must use {@link #attach(AttachCallback, Handler)} to initialize a 97 * Aware cluster - before making any other Aware operation. Aware cluster membership is a 98 * device-wide operation - the API guarantees that the device is in a cluster or joins a 99 * Aware cluster (or starts one if none can be found). Information about attach success (or 100 * failure) are returned in callbacks of {@link AttachCallback}. Proceed with Aware 101 * discovery or connection setup only after receiving confirmation that Aware attach 102 * succeeded - {@link AttachCallback#onAttached(WifiAwareSession)}. When an 103 * application is finished using Aware it <b>must</b> use the 104 * {@link WifiAwareSession#close()} API to indicate to the Aware service that the device 105 * may detach from the Aware cluster. The device will actually disable Aware once the last 106 * application detaches. 107 * <p> 108 * Once a Aware attach is confirmed use the 109 * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback, Handler)} 110 * or 111 * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback, 112 * Handler)} to create publish or subscribe Aware discovery sessions. Events are called on the 113 * provided callback object {@link DiscoverySessionCallback}. Specifically, the 114 * {@link DiscoverySessionCallback#onPublishStarted(PublishDiscoverySession)} 115 * and 116 * {@link DiscoverySessionCallback#onSubscribeStarted( 117 *SubscribeDiscoverySession)} 118 * return {@link PublishDiscoverySession} and 119 * {@link SubscribeDiscoverySession} 120 * objects respectively on which additional session operations can be performed, e.g. updating 121 * the session {@link PublishDiscoverySession#updatePublish(PublishConfig)} and 122 * {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. Sessions can 123 * also be used to send messages using the 124 * {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])} APIs. When an 125 * application is finished with a discovery session it <b>must</b> terminate it using the 126 * {@link DiscoverySession#close()} API. 127 * <p> 128 * Creating connections between Aware devices is managed by the standard 129 * {@link ConnectivityManager#requestNetwork(NetworkRequest, 130 * ConnectivityManager.NetworkCallback)}. 131 * The {@link NetworkRequest} object should be constructed with: 132 * <ul> 133 * <li>{@link NetworkRequest.Builder#addTransportType(int)} of 134 * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}. 135 * <li>{@link NetworkRequest.Builder#setNetworkSpecifier(String)} using 136 * {@link WifiAwareNetworkSpecifier.Builder}. 137 * </ul> 138 */ 139 @SystemService(Context.WIFI_AWARE_SERVICE) 140 public class WifiAwareManager { 141 private static final String TAG = "WifiAwareManager"; 142 private static final boolean DBG = false; 143 private static final boolean VDBG = false; // STOPSHIP if true 144 145 /** 146 * Broadcast intent action to indicate that the state of Wi-Fi Aware availability has changed 147 * and all active Aware sessions are no longer usable. Use the {@link #isAvailable()} to query 148 * the current status. 149 * This broadcast is <b>not</b> sticky, use the {@link #isAvailable()} API after registering 150 * the broadcast to check the current state of Wi-Fi Aware. 151 * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered 152 * components will be launched. 153 */ 154 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 155 public static final String ACTION_WIFI_AWARE_STATE_CHANGED = 156 "android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED"; 157 /** 158 * Intent broadcast sent whenever Wi-Fi Aware resource availability has changed. The resources 159 * are attached with the {@link #EXTRA_AWARE_RESOURCES} extra. The resources can also be 160 * obtained using the {@link #getAvailableAwareResources()} method. To receive this broadcast, 161 * apps must hold {@link android.Manifest.permission#ACCESS_WIFI_STATE}. 162 * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered 163 * components will be launched. 164 */ 165 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 166 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 167 @RequiresPermission(ACCESS_WIFI_STATE) 168 public static final String ACTION_WIFI_AWARE_RESOURCE_CHANGED = 169 "android.net.wifi.aware.action.WIFI_AWARE_RESOURCE_CHANGED"; 170 171 /** 172 * Sent as a part of {@link #ACTION_WIFI_AWARE_RESOURCE_CHANGED} that contains an instance of 173 * {@link AwareResources} representing the current Wi-Fi Aware resources. 174 */ 175 public static final String EXTRA_AWARE_RESOURCES = 176 "android.net.wifi.aware.extra.AWARE_RESOURCES"; 177 178 /** @hide */ 179 @IntDef({ 180 WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}) 181 @Retention(RetentionPolicy.SOURCE) 182 public @interface DataPathRole { 183 } 184 185 /** 186 * Connection creation role is that of INITIATOR. Used to create a network specifier string 187 * when requesting a Aware network. 188 * 189 * @see WifiAwareSession#createNetworkSpecifierOpen(int, byte[]) 190 * @see WifiAwareSession#createNetworkSpecifierPassphrase(int, byte[], String) 191 */ 192 public static final int WIFI_AWARE_DATA_PATH_ROLE_INITIATOR = 0; 193 194 /** 195 * Connection creation role is that of RESPONDER. Used to create a network specifier string 196 * when requesting a Aware network. 197 * 198 * @see WifiAwareSession#createNetworkSpecifierOpen(int, byte[]) 199 * @see WifiAwareSession#createNetworkSpecifierPassphrase(int, byte[], String) 200 */ 201 public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1; 202 203 /** @hide */ 204 @IntDef({ 205 WIFI_AWARE_DISCOVERY_LOST_REASON_UNKNOWN, 206 WIFI_AWARE_DISCOVERY_LOST_REASON_PEER_NOT_VISIBLE}) 207 @Retention(RetentionPolicy.SOURCE) 208 public @interface DiscoveryLostReasonCode { 209 } 210 211 /** 212 * Reason code provided in {@link DiscoverySessionCallback#onServiceLost(PeerHandle, int)} 213 * indicating that the service was lost for unknown reason. 214 */ 215 public static final int WIFI_AWARE_DISCOVERY_LOST_REASON_UNKNOWN = 0; 216 217 /** 218 * Reason code provided in {@link DiscoverySessionCallback#onServiceLost(PeerHandle, int)} 219 * indicating that the service advertised by the peer is no longer visible. This may be because 220 * the peer is out of range or because the peer stopped advertising this service. 221 */ 222 public static final int WIFI_AWARE_DISCOVERY_LOST_REASON_PEER_NOT_VISIBLE = 1; 223 224 /** @hide */ 225 @IntDef({ 226 WIFI_AWARE_SUSPEND_REDUNDANT_REQUEST, 227 WIFI_AWARE_SUSPEND_INVALID_SESSION, 228 WIFI_AWARE_SUSPEND_CANNOT_SUSPEND, 229 WIFI_AWARE_SUSPEND_INTERNAL_ERROR}) 230 @Retention(RetentionPolicy.SOURCE) 231 public @interface SessionSuspensionFailedReasonCode {} 232 233 /** 234 * Reason code provided in {@link DiscoverySessionCallback#onSessionSuspendFailed(int)} when the 235 * session is already suspended. 236 * @hide 237 */ 238 @SystemApi 239 public static final int WIFI_AWARE_SUSPEND_REDUNDANT_REQUEST = 0; 240 241 /** 242 * Reason code provided in {@link DiscoverySessionCallback#onSessionSuspendFailed(int)} when the 243 * specified session does not support suspension. 244 @hide 245 */ 246 @SystemApi 247 public static final int WIFI_AWARE_SUSPEND_INVALID_SESSION = 1; 248 249 /** 250 * Reason code provided in {@link DiscoverySessionCallback#onSessionSuspendFailed(int)} when the 251 * session could not be suspended due to more than one app using it. 252 @hide 253 */ 254 @SystemApi 255 public static final int WIFI_AWARE_SUSPEND_CANNOT_SUSPEND = 2; 256 257 /** 258 * Reason code provided in {@link DiscoverySessionCallback#onSessionSuspendFailed(int)} when an 259 * error is encountered with the request. 260 @hide 261 */ 262 @SystemApi 263 public static final int WIFI_AWARE_SUSPEND_INTERNAL_ERROR = 3; 264 265 /** @hide */ 266 @IntDef({ 267 WIFI_AWARE_RESUME_REDUNDANT_REQUEST, 268 WIFI_AWARE_RESUME_INVALID_SESSION, 269 WIFI_AWARE_RESUME_INTERNAL_ERROR}) 270 @Retention(RetentionPolicy.SOURCE) 271 public @interface SessionResumptionFailedReasonCode {} 272 273 /** 274 * Reason code provided in {@link DiscoverySessionCallback#onSessionResumeFailed(int)} when the 275 * session is not suspended. 276 * @hide 277 */ 278 @SystemApi 279 public static final int WIFI_AWARE_RESUME_REDUNDANT_REQUEST = 0; 280 281 /** 282 * Reason code provided in {@link DiscoverySessionCallback#onSessionResumeFailed(int)} when the 283 * specified session does not support suspension. 284 @hide 285 */ 286 @SystemApi 287 public static final int WIFI_AWARE_RESUME_INVALID_SESSION = 1; 288 289 /** 290 * Reason code provided in {@link DiscoverySessionCallback#onSessionResumeFailed(int)} when an 291 * error is encountered with the request. 292 @hide 293 */ 294 @SystemApi 295 public static final int WIFI_AWARE_RESUME_INTERNAL_ERROR = 2; 296 297 /** @hide */ 298 @Retention(RetentionPolicy.SOURCE) 299 @IntDef( 300 prefix = {"WIFI_BAND_"}, 301 value = {WIFI_BAND_24_GHZ, WIFI_BAND_5_GHZ}) 302 public @interface InstantModeBand {}; 303 304 private final Context mContext; 305 private final IWifiAwareManager mService; 306 307 private final Object mLock = new Object(); // lock access to the following vars 308 309 /** @hide */ WifiAwareManager(@onNull Context context, @NonNull IWifiAwareManager service)310 public WifiAwareManager(@NonNull Context context, @NonNull IWifiAwareManager service) { 311 mContext = context; 312 mService = service; 313 } 314 315 /** 316 * Returns the current status of Aware API: whether or not Aware is available. To track 317 * changes in the state of Aware API register for the 318 * {@link #ACTION_WIFI_AWARE_STATE_CHANGED} broadcast. 319 * 320 * @return A boolean indicating whether the app can use the Aware API at this time (true) or 321 * not (false). 322 */ 323 @RequiresPermission(ACCESS_WIFI_STATE) isAvailable()324 public boolean isAvailable() { 325 try { 326 return mService.isUsageEnabled(); 327 } catch (RemoteException e) { 328 throw e.rethrowFromSystemServer(); 329 } 330 } 331 332 /** 333 * Return the current status of the Aware service: whether or not the device is already attached 334 * to an Aware cluster. To attach to an Aware cluster, please use 335 * {@link #attach(AttachCallback, Handler)} or 336 * {@link #attach(AttachCallback, IdentityChangedListener, Handler)}. 337 * @return A boolean indicating whether the device is attached to a cluster at this time (true) 338 * or not (false). 339 */ 340 @RequiresPermission(ACCESS_WIFI_STATE) isDeviceAttached()341 public boolean isDeviceAttached() { 342 try { 343 return mService.isDeviceAttached(); 344 } catch (RemoteException e) { 345 throw e.rethrowFromSystemServer(); 346 } 347 } 348 349 /** 350 * Return the device support for setting a channel requirement in a data-path request. If true 351 * the channel set by 352 * {@link WifiAwareNetworkSpecifier.Builder#setChannelFrequencyMhz(int, boolean)} will be 353 * honored, otherwise it will be ignored. 354 * @return True is the device support set channel on data-path request, false otherwise. 355 */ 356 @RequiresPermission(ACCESS_WIFI_STATE) isSetChannelOnDataPathSupported()357 public boolean isSetChannelOnDataPathSupported() { 358 try { 359 return mService.isSetChannelOnDataPathSupported(); 360 } catch (RemoteException e) { 361 throw e.rethrowFromSystemServer(); 362 } 363 } 364 365 /** 366 * Enable the Wifi Aware Instant communication mode. If the device doesn't support this feature 367 * calling this API will result no action. 368 * <p> 369 * Note: before {@link android.os.Build.VERSION_CODES#TIRAMISU}, only system app can use this 370 * API. Start with {@link android.os.Build.VERSION_CODES#TIRAMISU} apps hold 371 * {@link android.Manifest.permission#OVERRIDE_WIFI_CONFIG} are allowed to use it. 372 * 373 * @see Characteristics#isInstantCommunicationModeSupported() 374 * @param enable true for enable, false otherwise. 375 * @hide 376 */ 377 @SystemApi 378 @RequiresApi(Build.VERSION_CODES.S) 379 @RequiresPermission(allOf = {CHANGE_WIFI_STATE, OVERRIDE_WIFI_CONFIG}) enableInstantCommunicationMode(boolean enable)380 public void enableInstantCommunicationMode(boolean enable) { 381 if (!SdkLevel.isAtLeastS()) { 382 throw new UnsupportedOperationException(); 383 } 384 try { 385 mService.enableInstantCommunicationMode(mContext.getOpPackageName(), enable); 386 } catch (RemoteException e) { 387 throw e.rethrowFromSystemServer(); 388 } 389 } 390 391 /** 392 * Return the current status of the Wifi Aware instant communication mode. 393 * If the device doesn't support this feature, return will always be false. 394 * @see Characteristics#isInstantCommunicationModeSupported() 395 * @return true if it is enabled, false otherwise. 396 */ 397 @RequiresApi(Build.VERSION_CODES.S) 398 @RequiresPermission(ACCESS_WIFI_STATE) isInstantCommunicationModeEnabled()399 public boolean isInstantCommunicationModeEnabled() { 400 if (!SdkLevel.isAtLeastS()) { 401 throw new UnsupportedOperationException(); 402 } 403 try { 404 return mService.isInstantCommunicationModeEnabled(); 405 } catch (RemoteException e) { 406 throw e.rethrowFromSystemServer(); 407 } 408 } 409 410 /** 411 * Returns the characteristics of the Wi-Fi Aware interface: a set of parameters which specify 412 * limitations on configurations, e.g. the maximum service name length. 413 * <p> 414 * May return {@code null} if the Wi-Fi Aware service is not initialized. Use 415 * {@link #attach(AttachCallback, Handler)} or 416 * {@link #attach(AttachCallback, IdentityChangedListener, Handler)} to initialize the Wi-Fi 417 * Aware service. 418 * 419 * @return An object specifying configuration limitations of Aware. 420 */ 421 @RequiresPermission(ACCESS_WIFI_STATE) getCharacteristics()422 public @Nullable Characteristics getCharacteristics() { 423 try { 424 return mService.getCharacteristics(); 425 } catch (RemoteException e) { 426 throw e.rethrowFromSystemServer(); 427 } 428 } 429 430 /** 431 * Return the available resources of the Wi-Fi aware service: a set of parameters which specify 432 * limitations on service usage, e.g the number of data-paths which could be created. 433 * <p> 434 * May return {@code null} if the Wi-Fi Aware service is not initialized. Use 435 * {@link #attach(AttachCallback, Handler)} or 436 * {@link #attach(AttachCallback, IdentityChangedListener, Handler)} to initialize the Wi-Fi 437 * Aware service. 438 * 439 * @return An object specifying the currently available resource of the Wi-Fi Aware service. 440 */ 441 @RequiresPermission(ACCESS_WIFI_STATE) getAvailableAwareResources()442 public @Nullable AwareResources getAvailableAwareResources() { 443 try { 444 return mService.getAvailableAwareResources(); 445 } catch (RemoteException e) { 446 throw e.rethrowFromSystemServer(); 447 } 448 } 449 450 /** 451 * Attach to the Wi-Fi Aware service - enabling the application to create discovery sessions or 452 * create connections to peers. The device will attach to an existing cluster if it can find 453 * one or create a new cluster (if it is the first to enable Aware in its vicinity). Results 454 * (e.g. successful attach to a cluster) are provided to the {@code attachCallback} object. 455 * An application <b>must</b> call {@link WifiAwareSession#close()} when done with the 456 * Wi-Fi Aware object. 457 * <p> 458 * Note: a Aware cluster is a shared resource - if the device is already attached to a cluster 459 * then this function will simply indicate success immediately using the same {@code 460 * attachCallback}. 461 * 462 * @param attachCallback A callback for attach events, extended from 463 * {@link AttachCallback}. 464 * @param handler The Handler on whose thread to execute the callbacks of the {@code 465 * attachCallback} object. If a null is provided then the application's main thread will be 466 * used. 467 */ 468 @RequiresPermission(allOf = { 469 ACCESS_WIFI_STATE, 470 CHANGE_WIFI_STATE 471 }) attach(@onNull AttachCallback attachCallback, @Nullable Handler handler)472 public void attach(@NonNull AttachCallback attachCallback, @Nullable Handler handler) { 473 attach(handler, null, attachCallback, null, false, null); 474 } 475 476 /** 477 * Attach to the Wi-Fi Aware service - enabling the application to create discovery sessions or 478 * create connections to peers. The device will attach to an existing cluster if it can find 479 * one or create a new cluster (if it is the first to enable Aware in its vicinity). Results 480 * (e.g. successful attach to a cluster) are provided to the {@code attachCallback} object. 481 * An application <b>must</b> call {@link WifiAwareSession#close()} when done with the 482 * Wi-Fi Aware object. 483 * <p> 484 * Note: a Aware cluster is a shared resource - if the device is already attached to a cluster 485 * then this function will simply indicate success immediately using the same {@code 486 * attachCallback}. 487 * <p> 488 * This version of the API attaches a listener to receive the MAC address of the Aware interface 489 * on startup and whenever it is updated (it is randomized at regular intervals for privacy). 490 * 491 * If targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later, the application must 492 * have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with 493 * android:usesPermissionFlags="neverForLocation". If the application does not declare 494 * android:usesPermissionFlags="neverForLocation", then it must also have 495 * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}. 496 * 497 * If targeting an earlier release than {@link android.os.Build.VERSION_CODES#TIRAMISU}, the 498 * application must have {@link android.Manifest.permission#ACCESS_FINE_LOCATION}. 499 * 500 * Apps without {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} or 501 * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} can use the 502 * {@link #attach(AttachCallback, Handler)} version. 503 * Note that aside from permission requirements the {@link IdentityChangedListener} will wake up 504 * the host at regular intervals causing higher power consumption, do not use it unless the 505 * information is necessary (e.g. for out-of-band discovery). 506 * 507 * @param attachCallback A callback for attach events, extended from 508 * {@link AttachCallback}. 509 * @param identityChangedListener A callback for changed identity or cluster ID, extended from 510 * {@link IdentityChangedListener}. 511 * @param handler The Handler on whose thread to execute the callbacks of the {@code 512 * attachCallback} and {@code identityChangedListener} objects. If a null is provided then the 513 * application's main thread will be used. 514 */ 515 @RequiresPermission(allOf = { 516 ACCESS_WIFI_STATE, 517 CHANGE_WIFI_STATE, 518 ACCESS_FINE_LOCATION, 519 NEARBY_WIFI_DEVICES}, conditional = true) attach(@onNull AttachCallback attachCallback, @NonNull IdentityChangedListener identityChangedListener, @Nullable Handler handler)520 public void attach(@NonNull AttachCallback attachCallback, 521 @NonNull IdentityChangedListener identityChangedListener, 522 @Nullable Handler handler) { 523 attach(handler, null, attachCallback, identityChangedListener, false, null); 524 } 525 526 /** 527 * Attach to the Wi-Fi Aware service - enabling the application to create discovery sessions or 528 * create connections to peers. See {@link #attach(AttachCallback, IdentityChangedListener, 529 * Handler)} for more information. 530 * 531 * This version allows callers to provide an instance of {@link ConfigRequest}. 532 * 533 * @param configRequest Parameters for this request. 534 * @param executor The executor to execute the listener of the {@code attachCallback} object. 535 * @param attachCallback A callback for attach events, extended from {@link AttachCallback}. 536 * @param identityChangedListener A callback for changed identity or cluster ID, extended from 537 * {@link IdentityChangedListener}. 538 * @hide 539 */ 540 @RequiresPermission(allOf = { 541 ACCESS_WIFI_STATE, 542 CHANGE_WIFI_STATE, 543 ACCESS_FINE_LOCATION, 544 NEARBY_WIFI_DEVICES, 545 MANAGE_WIFI_NETWORK_SELECTION}, conditional = true) 546 @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) 547 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) 548 @SystemApi attach(@onNull ConfigRequest configRequest, @NonNull @CallbackExecutor Executor executor, @NonNull AttachCallback attachCallback, @NonNull IdentityChangedListener identityChangedListener)549 public void attach(@NonNull ConfigRequest configRequest, 550 @NonNull @CallbackExecutor Executor executor, @NonNull AttachCallback attachCallback, 551 @NonNull IdentityChangedListener identityChangedListener) { 552 if (!SdkLevel.isAtLeastV()) { 553 throw new UnsupportedOperationException(); 554 } 555 Objects.requireNonNull(configRequest); 556 Objects.requireNonNull(executor); 557 attach(null, configRequest, attachCallback, identityChangedListener, false, executor); 558 } 559 560 /** @hide */ attach(Handler handler, ConfigRequest configRequest, AttachCallback attachCallback, IdentityChangedListener identityChangedListener, boolean forOffloading, Executor executor)561 public void attach(Handler handler, ConfigRequest configRequest, 562 AttachCallback attachCallback, 563 IdentityChangedListener identityChangedListener, boolean forOffloading, 564 Executor executor) { 565 if (VDBG) { 566 Log.v(TAG, "attach(): handler=" + handler + ", callback=" + attachCallback 567 + ", configRequest=" + configRequest + ", identityChangedListener=" 568 + identityChangedListener + ", forOffloading" + forOffloading); 569 } 570 571 if (attachCallback == null) { 572 throw new IllegalArgumentException("Null callback provided"); 573 } 574 575 synchronized (mLock) { 576 Executor localExecutor = executor; 577 if (localExecutor == null) { 578 localExecutor = new HandlerExecutor((handler == null) 579 ? new Handler(Looper.getMainLooper()) : handler); 580 } 581 582 try { 583 Binder binder = new Binder(); 584 Bundle extras = new Bundle(); 585 if (SdkLevel.isAtLeastS()) { 586 extras.putParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE, 587 mContext.getAttributionSource()); 588 } 589 mService.connect(binder, mContext.getOpPackageName(), mContext.getAttributionTag(), 590 new WifiAwareEventCallbackProxy(this, localExecutor, binder, 591 attachCallback, identityChangedListener), configRequest, 592 identityChangedListener != null, extras, forOffloading); 593 } catch (RemoteException e) { 594 throw e.rethrowFromSystemServer(); 595 } 596 } 597 } 598 599 /** @hide */ disconnect(int clientId, Binder binder)600 public void disconnect(int clientId, Binder binder) { 601 if (VDBG) Log.v(TAG, "disconnect()"); 602 603 try { 604 mService.disconnect(clientId, binder); 605 } catch (RemoteException e) { 606 throw e.rethrowFromSystemServer(); 607 } 608 } 609 610 /** @hide */ setMasterPreference(int clientId, Binder binder, int mp)611 public void setMasterPreference(int clientId, Binder binder, int mp) { 612 if (VDBG) Log.v(TAG, "setMasterPreference()"); 613 614 try { 615 mService.setMasterPreference(clientId, binder, mp); 616 } catch (RemoteException e) { 617 throw e.rethrowFromSystemServer(); 618 } 619 } 620 621 /** 622 * @hide 623 */ getMasterPreference(int clientId, Binder binder, @NonNull Executor executor, @NonNull Consumer<Integer> resultsCallback)624 public void getMasterPreference(int clientId, Binder binder, @NonNull Executor executor, 625 @NonNull Consumer<Integer> resultsCallback) { 626 Objects.requireNonNull(executor, "executor cannot be null"); 627 Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null"); 628 try { 629 mService.getMasterPreference(clientId, binder, 630 new IIntegerListener.Stub() { 631 public void onResult(int value) { 632 Binder.clearCallingIdentity(); 633 executor.execute(() -> resultsCallback.accept(value)); 634 } 635 }); 636 } catch (RemoteException e) { 637 throw e.rethrowFromSystemServer(); 638 } 639 } 640 641 /** @hide */ publish(int clientId, Looper looper, PublishConfig publishConfig, DiscoverySessionCallback callback)642 public void publish(int clientId, Looper looper, PublishConfig publishConfig, 643 DiscoverySessionCallback callback) { 644 if (VDBG) Log.v(TAG, "publish(): clientId=" + clientId + ", config=" + publishConfig); 645 646 if (callback == null) { 647 throw new IllegalArgumentException("Null callback provided"); 648 } 649 650 try { 651 Bundle extras = new Bundle(); 652 if (SdkLevel.isAtLeastS()) { 653 extras.putParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE, 654 mContext.getAttributionSource()); 655 } 656 mService.publish(mContext.getOpPackageName(), mContext.getAttributionTag(), clientId, 657 publishConfig, 658 new WifiAwareDiscoverySessionCallbackProxy(this, looper, true, callback, 659 clientId), extras); 660 } catch (RemoteException e) { 661 throw e.rethrowFromSystemServer(); 662 } 663 } 664 665 /** @hide */ updatePublish(int clientId, int sessionId, PublishConfig publishConfig)666 public void updatePublish(int clientId, int sessionId, PublishConfig publishConfig) { 667 if (VDBG) { 668 Log.v(TAG, "updatePublish(): clientId=" + clientId + ",sessionId=" + sessionId 669 + ", config=" + publishConfig); 670 } 671 672 try { 673 mService.updatePublish(clientId, sessionId, publishConfig); 674 } catch (RemoteException e) { 675 throw e.rethrowFromSystemServer(); 676 } 677 } 678 679 /** @hide */ subscribe(int clientId, Looper looper, SubscribeConfig subscribeConfig, DiscoverySessionCallback callback)680 public void subscribe(int clientId, Looper looper, SubscribeConfig subscribeConfig, 681 DiscoverySessionCallback callback) { 682 if (VDBG) { 683 if (VDBG) { 684 Log.v(TAG, 685 "subscribe(): clientId=" + clientId + ", config=" + subscribeConfig); 686 } 687 } 688 689 if (callback == null) { 690 throw new IllegalArgumentException("Null callback provided"); 691 } 692 693 try { 694 Bundle extras = new Bundle(); 695 if (SdkLevel.isAtLeastS()) { 696 extras.putParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE, 697 mContext.getAttributionSource()); 698 } 699 mService.subscribe(mContext.getOpPackageName(), mContext.getAttributionTag(), clientId, 700 subscribeConfig, 701 new WifiAwareDiscoverySessionCallbackProxy(this, looper, false, callback, 702 clientId), extras); 703 } catch (RemoteException e) { 704 throw e.rethrowFromSystemServer(); 705 } 706 } 707 708 /** @hide */ updateSubscribe(int clientId, int sessionId, SubscribeConfig subscribeConfig)709 public void updateSubscribe(int clientId, int sessionId, SubscribeConfig subscribeConfig) { 710 if (VDBG) { 711 Log.v(TAG, "updateSubscribe(): clientId=" + clientId + ",sessionId=" + sessionId 712 + ", config=" + subscribeConfig); 713 } 714 715 try { 716 mService.updateSubscribe(clientId, sessionId, subscribeConfig); 717 } catch (RemoteException e) { 718 throw e.rethrowFromSystemServer(); 719 } 720 } 721 722 /** @hide */ terminateSession(int clientId, int sessionId)723 public void terminateSession(int clientId, int sessionId) { 724 if (VDBG) { 725 Log.d(TAG, 726 "terminateSession(): clientId=" + clientId + ", sessionId=" + sessionId); 727 } 728 729 try { 730 mService.terminateSession(clientId, sessionId); 731 } catch (RemoteException e) { 732 throw e.rethrowFromSystemServer(); 733 } 734 } 735 736 /** @hide */ sendMessage(int clientId, int sessionId, PeerHandle peerHandle, byte[] message, int messageId, int retryCount)737 public void sendMessage(int clientId, int sessionId, PeerHandle peerHandle, byte[] message, 738 int messageId, int retryCount) { 739 if (peerHandle == null) { 740 throw new IllegalArgumentException( 741 "sendMessage: invalid peerHandle - must be non-null"); 742 } 743 744 if (VDBG) { 745 Log.v(TAG, "sendMessage(): clientId=" + clientId + ", sessionId=" + sessionId 746 + ", peerHandle=" + peerHandle.peerId + ", messageId=" 747 + messageId + ", retryCount=" + retryCount); 748 } 749 750 try { 751 mService.sendMessage(clientId, sessionId, peerHandle.peerId, message, messageId, 752 retryCount); 753 } catch (RemoteException e) { 754 throw e.rethrowFromSystemServer(); 755 } 756 } 757 758 /** 759 * @hide 760 */ initiateNanPairingSetupRequest(int clientId, int sessionId, PeerHandle peerHandle, String password, String pairingDeviceAlias, int cipherSuite)761 public void initiateNanPairingSetupRequest(int clientId, int sessionId, PeerHandle peerHandle, 762 String password, String pairingDeviceAlias, int cipherSuite) { 763 if (peerHandle == null) { 764 throw new IllegalArgumentException( 765 "initiateNanPairingRequest: invalid peerHandle - must be non-null"); 766 } 767 if (VDBG) { 768 Log.v(TAG, "initiateNanPairingRequest(): clientId=" + clientId 769 + ", sessionId=" + sessionId + ", peerHandle=" + peerHandle.peerId); 770 } 771 try { 772 mService.initiateNanPairingSetupRequest(clientId, sessionId, peerHandle.peerId, 773 password, pairingDeviceAlias, cipherSuite); 774 } catch (RemoteException e) { 775 throw e.rethrowFromSystemServer(); 776 } 777 } 778 779 /** 780 * @hide 781 */ responseNanPairingSetupRequest(int clientId, int sessionId, PeerHandle peerHandle, int requestId, String password, String pairingDeviceAlias, boolean accept, int cipherSuite)782 public void responseNanPairingSetupRequest(int clientId, int sessionId, PeerHandle peerHandle, 783 int requestId, String password, String pairingDeviceAlias, boolean accept, 784 int cipherSuite) { 785 if (peerHandle == null) { 786 throw new IllegalArgumentException( 787 "initiateNanPairingRequest: invalid peerHandle - must be non-null"); 788 } 789 if (VDBG) { 790 Log.v(TAG, "initiateNanPairingRequest(): clientId=" + clientId 791 + ", sessionId=" + sessionId + ", peerHandle=" + peerHandle.peerId); 792 } 793 try { 794 mService.responseNanPairingSetupRequest(clientId, sessionId, peerHandle.peerId, 795 requestId, password, pairingDeviceAlias, accept, cipherSuite); 796 } catch (RemoteException e) { 797 throw e.rethrowFromSystemServer(); 798 } 799 } 800 801 /** 802 * @hide 803 */ initiateBootStrappingSetupRequest(int clientId, int sessionId, PeerHandle peerHandle, int method)804 public void initiateBootStrappingSetupRequest(int clientId, int sessionId, 805 PeerHandle peerHandle, int method) { 806 if (peerHandle == null) { 807 throw new IllegalArgumentException( 808 "initiateBootStrappingSetupRequest: invalid peerHandle - must be non-null"); 809 } 810 if (VDBG) { 811 Log.v(TAG, "initiateBootStrappingSetupRequest(): clientId=" + clientId 812 + ", sessionId=" + sessionId + ", peerHandle=" + peerHandle.peerId); 813 } 814 try { 815 mService.initiateBootStrappingSetupRequest(clientId, sessionId, peerHandle.peerId, 816 method); 817 } catch (RemoteException e) { 818 throw e.rethrowFromSystemServer(); 819 } 820 } 821 822 /** @hide */ 823 @RequiresPermission(android.Manifest.permission.NETWORK_STACK) requestMacAddresses(int uid, int[] peerIds, IWifiAwareMacAddressProvider callback)824 public void requestMacAddresses(int uid, int[] peerIds, 825 IWifiAwareMacAddressProvider callback) { 826 try { 827 mService.requestMacAddresses(uid, peerIds, callback); 828 } catch (RemoteException e) { 829 throw e.rethrowFromSystemServer(); 830 } 831 } 832 833 /** @hide */ createNetworkSpecifier(int clientId, int role, int sessionId, @NonNull PeerHandle peerHandle, @Nullable byte[] pmk, @Nullable String passphrase)834 public NetworkSpecifier createNetworkSpecifier(int clientId, int role, int sessionId, 835 @NonNull PeerHandle peerHandle, @Nullable byte[] pmk, @Nullable String passphrase) { 836 if (VDBG) { 837 Log.v(TAG, "createNetworkSpecifier: role=" + role + ", sessionId=" + sessionId 838 + ", peerHandle=" + ((peerHandle == null) ? peerHandle : peerHandle.peerId) 839 + ", pmk=" + ((pmk == null) ? "null" : "non-null") 840 + ", passphrase=" + ((passphrase == null) ? "null" : "non-null")); 841 } 842 843 if (!WifiAwareUtils.isLegacyVersion(mContext, Build.VERSION_CODES.Q)) { 844 throw new UnsupportedOperationException( 845 "API deprecated - use WifiAwareNetworkSpecifier.Builder"); 846 } 847 848 if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR 849 && role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) { 850 throw new IllegalArgumentException( 851 "createNetworkSpecifier: Invalid 'role' argument when creating a network " 852 + "specifier"); 853 } 854 if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR || !WifiAwareUtils.isLegacyVersion(mContext, 855 Build.VERSION_CODES.P)) { 856 if (peerHandle == null) { 857 throw new IllegalArgumentException( 858 "createNetworkSpecifier: Invalid peer handle - cannot be null"); 859 } 860 } 861 862 return new WifiAwareNetworkSpecifier( 863 (peerHandle == null) ? WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB_ANY_PEER 864 : WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB, 865 role, 866 clientId, 867 sessionId, 868 peerHandle != null ? peerHandle.peerId : 0, // 0 is an invalid peer ID 869 null, // peerMac (not used in this method) 870 pmk, 871 passphrase, 872 0, // no port info for deprecated IB APIs 873 -1); // no transport info for deprecated IB APIs 874 } 875 876 /** @hide */ createNetworkSpecifier(int clientId, @DataPathRole int role, @NonNull byte[] peer, @Nullable byte[] pmk, @Nullable String passphrase)877 public NetworkSpecifier createNetworkSpecifier(int clientId, @DataPathRole int role, 878 @NonNull byte[] peer, @Nullable byte[] pmk, @Nullable String passphrase) { 879 if (VDBG) { 880 Log.v(TAG, "createNetworkSpecifier: role=" + role 881 + ", pmk=" + ((pmk == null) ? "null" : "non-null") 882 + ", passphrase=" + ((passphrase == null) ? "null" : "non-null")); 883 } 884 885 if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR 886 && role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) { 887 throw new IllegalArgumentException( 888 "createNetworkSpecifier: Invalid 'role' argument when creating a network " 889 + "specifier"); 890 } 891 if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR || !WifiAwareUtils.isLegacyVersion(mContext, 892 Build.VERSION_CODES.P)) { 893 if (peer == null) { 894 throw new IllegalArgumentException( 895 "createNetworkSpecifier: Invalid peer MAC - cannot be null"); 896 } 897 } 898 if (peer != null && peer.length != 6) { 899 throw new IllegalArgumentException("createNetworkSpecifier: Invalid peer MAC address"); 900 } 901 902 return new WifiAwareNetworkSpecifier( 903 (peer == null) ? WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER 904 : WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB, 905 role, 906 clientId, 907 0, // 0 is an invalid session ID 908 0, // 0 is an invalid peer ID 909 peer, 910 pmk, 911 passphrase, 912 0, // no port info for OOB APIs 913 -1); // no transport protocol info for OOB APIs 914 } 915 916 private static class WifiAwareEventCallbackProxy extends IWifiAwareEventCallback.Stub { 917 private final WeakReference<WifiAwareManager> mAwareManager; 918 private final Binder mBinder; 919 private final Executor mExecutor; 920 921 private final AttachCallback mAttachCallback; 922 923 private final IdentityChangedListener mIdentityChangedListener; 924 925 /** 926 * Constructs a {@link AttachCallback} using the specified looper. 927 * All callbacks will delivered on the thread of the specified looper. 928 * 929 * @param executor The executor to execute the callbacks. 930 */ WifiAwareEventCallbackProxy(WifiAwareManager mgr, Executor executor, Binder binder, final AttachCallback attachCallback, final IdentityChangedListener identityChangedListener)931 WifiAwareEventCallbackProxy(WifiAwareManager mgr, Executor executor, Binder binder, 932 final AttachCallback attachCallback, 933 final IdentityChangedListener identityChangedListener) { 934 mAwareManager = new WeakReference<>(mgr); 935 mExecutor = executor; 936 mBinder = binder; 937 mAttachCallback = attachCallback; 938 mIdentityChangedListener = identityChangedListener; 939 } 940 941 @Override onConnectSuccess(int clientId)942 public void onConnectSuccess(int clientId) { 943 if (VDBG) Log.v(TAG, "onConnectSuccess"); 944 Binder.clearCallingIdentity(); 945 mExecutor.execute(() -> { 946 WifiAwareManager mgr = mAwareManager.get(); 947 if (mgr == null) { 948 Log.w(TAG, "WifiAwareEventCallbackProxy: handleMessage post GC"); 949 return; 950 } 951 mAttachCallback.onAttached(new WifiAwareSession(mgr, mBinder, clientId)); 952 }); 953 } 954 955 @Override onConnectFail(int reason)956 public void onConnectFail(int reason) { 957 if (VDBG) Log.v(TAG, "onConnectFail: reason=" + reason); 958 Binder.clearCallingIdentity(); 959 mExecutor.execute(() -> { 960 WifiAwareManager mgr = mAwareManager.get(); 961 if (mgr == null) { 962 Log.w(TAG, "WifiAwareEventCallbackProxy: handleMessage post GC"); 963 return; 964 } 965 mAwareManager.clear(); 966 mAttachCallback.onAttachFailed(); 967 }); 968 } 969 970 @Override onIdentityChanged(byte[] mac)971 public void onIdentityChanged(byte[] mac) { 972 if (VDBG) Log.v(TAG, "onIdentityChanged: mac=" + new String(HexEncoding.encode(mac))); 973 Binder.clearCallingIdentity(); 974 mExecutor.execute(() -> { 975 WifiAwareManager mgr = mAwareManager.get(); 976 if (mgr == null) { 977 Log.w(TAG, "WifiAwareEventCallbackProxy: handleMessage post GC"); 978 return; 979 } 980 if (mIdentityChangedListener == null) { 981 Log.e(TAG, "CALLBACK_IDENTITY_CHANGED: null listener."); 982 } else { 983 mIdentityChangedListener.onIdentityChanged(mac); 984 } 985 }); 986 } 987 988 @Override onAttachTerminate()989 public void onAttachTerminate() { 990 if (VDBG) Log.v(TAG, "onAwareSessionTerminated"); 991 Binder.clearCallingIdentity(); 992 mExecutor.execute(() -> { 993 WifiAwareManager mgr = mAwareManager.get(); 994 if (mgr == null) { 995 Log.w(TAG, "WifiAwareEventCallbackProxy: handleMessage post GC"); 996 return; 997 } 998 mAwareManager.clear(); 999 mAttachCallback.onAwareSessionTerminated(); 1000 }); 1001 } 1002 1003 @Override onClusterIdChanged( @dentityChangedListener.ClusterChangeEvent int clusterEventType, byte[] clusterId)1004 public void onClusterIdChanged( 1005 @IdentityChangedListener.ClusterChangeEvent int clusterEventType, 1006 byte[] clusterId) { 1007 Binder.clearCallingIdentity(); 1008 mExecutor.execute(() -> { 1009 WifiAwareManager mgr = mAwareManager.get(); 1010 if (mgr == null) { 1011 Log.w(TAG, "WifiAwareEventCallbackProxy: handleMessage post GC"); 1012 return; 1013 } 1014 if (mIdentityChangedListener == null) { 1015 Log.e(TAG, "CALLBACK_CLUSTER_ID_CHANGED: null listener."); 1016 } else { 1017 try { 1018 mIdentityChangedListener.onClusterIdChanged( 1019 clusterEventType, MacAddress.fromBytes(clusterId)); 1020 } catch (IllegalArgumentException iae) { 1021 Log.e(TAG, " Invalid MAC address, " + iae); 1022 } 1023 } 1024 }); 1025 } 1026 } 1027 1028 private static class WifiAwareDiscoverySessionCallbackProxy extends 1029 IWifiAwareDiscoverySessionCallback.Stub { 1030 private final WeakReference<WifiAwareManager> mAwareManager; 1031 private final boolean mIsPublish; 1032 private final DiscoverySessionCallback mOriginalCallback; 1033 private final int mClientId; 1034 1035 private final Handler mHandler; 1036 private DiscoverySession mSession; 1037 WifiAwareDiscoverySessionCallbackProxy(WifiAwareManager mgr, Looper looper, boolean isPublish, DiscoverySessionCallback originalCallback, int clientId)1038 WifiAwareDiscoverySessionCallbackProxy(WifiAwareManager mgr, Looper looper, 1039 boolean isPublish, DiscoverySessionCallback originalCallback, 1040 int clientId) { 1041 mAwareManager = new WeakReference<>(mgr); 1042 mIsPublish = isPublish; 1043 mOriginalCallback = originalCallback; 1044 mClientId = clientId; 1045 1046 if (VDBG) { 1047 Log.v(TAG, "WifiAwareDiscoverySessionCallbackProxy ctor: isPublish=" + isPublish); 1048 } 1049 1050 mHandler = new Handler(looper); 1051 } 1052 1053 @Override onSessionStarted(int sessionId)1054 public void onSessionStarted(int sessionId) { 1055 if (VDBG) Log.v(TAG, "onSessionStarted: sessionId=" + sessionId); 1056 mHandler.post(() -> onProxySessionStarted(sessionId)); 1057 } 1058 1059 @Override onSessionConfigSuccess()1060 public void onSessionConfigSuccess() { 1061 if (VDBG) Log.v(TAG, "onSessionConfigSuccess"); 1062 mHandler.post(mOriginalCallback::onSessionConfigUpdated); 1063 } 1064 1065 @Override onSessionConfigFail(int reason)1066 public void onSessionConfigFail(int reason) { 1067 if (VDBG) Log.v(TAG, "onSessionConfigFail: reason=" + reason); 1068 mHandler.post(() -> { 1069 mOriginalCallback.onSessionConfigFailed(); 1070 if (mSession == null) { 1071 /* creation failed (as opposed to update failing) */ 1072 mAwareManager.clear(); 1073 } 1074 }); 1075 } 1076 1077 @Override onSessionTerminated(int reason)1078 public void onSessionTerminated(int reason) { 1079 if (VDBG) Log.v(TAG, "onSessionTerminated: reason=" + reason); 1080 mHandler.post(() -> onProxySessionTerminated(reason)); 1081 } 1082 1083 @Override onSessionSuspendSucceeded()1084 public void onSessionSuspendSucceeded() { 1085 if (VDBG) Log.v(TAG, "onSessionSuspendSucceeded"); 1086 mHandler.post(mOriginalCallback::onSessionSuspendSucceeded); 1087 } 1088 1089 @Override onSessionSuspendFail(int reason)1090 public void onSessionSuspendFail(int reason) { 1091 if (VDBG) Log.v(TAG, "onSessionSuspendFail: reason=" + reason); 1092 mHandler.post(() -> mOriginalCallback.onSessionSuspendFailed(reason)); 1093 } 1094 1095 @Override onSessionResumeSucceeded()1096 public void onSessionResumeSucceeded() { 1097 if (VDBG) Log.v(TAG, "onSessionResumeSucceeded"); 1098 mHandler.post(mOriginalCallback::onSessionResumeSucceeded); 1099 } 1100 1101 @Override onSessionResumeFail(int reason)1102 public void onSessionResumeFail(int reason) { 1103 if (VDBG) Log.v(TAG, "onSessionResumeFail: reason=" + reason); 1104 mHandler.post(() -> mOriginalCallback.onSessionResumeFailed(reason)); 1105 } 1106 1107 @Override onMatch(int peerId, byte[] serviceSpecificInfo, byte[] matchFilter, int peerCipherSuite, byte[] scid, String pairingAlias, AwarePairingConfig pairingConfig, @Nullable OuiKeyedData[] vendorData)1108 public void onMatch(int peerId, byte[] serviceSpecificInfo, byte[] matchFilter, 1109 int peerCipherSuite, byte[] scid, String pairingAlias, 1110 AwarePairingConfig pairingConfig, @Nullable OuiKeyedData[] vendorData) { 1111 if (VDBG) Log.v(TAG, "onMatch: peerId=" + peerId); 1112 1113 mHandler.post(() -> { 1114 List<byte[]> matchFilterList = getMatchFilterList(matchFilter); 1115 mOriginalCallback.onServiceDiscovered(new PeerHandle(peerId), serviceSpecificInfo, 1116 matchFilterList); 1117 mOriginalCallback.onServiceDiscovered( 1118 new ServiceDiscoveryInfo(new PeerHandle(peerId), peerCipherSuite, 1119 serviceSpecificInfo, matchFilterList, scid, pairingAlias, 1120 pairingConfig, vendorData)); 1121 }); 1122 } 1123 getMatchFilterList(byte[] matchFilter)1124 private List<byte[]> getMatchFilterList(byte[] matchFilter) { 1125 List<byte[]> matchFilterList = null; 1126 try { 1127 matchFilterList = new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList(); 1128 } catch (BufferOverflowException e) { 1129 matchFilterList = Collections.emptyList(); 1130 Log.e(TAG, "onServiceDiscovered: invalid match filter byte array '" 1131 + new String(HexEncoding.encode(matchFilter)) 1132 + "' - cannot be parsed: e=" + e); 1133 } 1134 return matchFilterList; 1135 } 1136 1137 @Override onMatchWithDistance(int peerId, byte[] serviceSpecificInfo, byte[] matchFilter, int distanceMm, int peerCipherSuite, byte[] scid, String pairingAlias, AwarePairingConfig pairingConfig, @Nullable OuiKeyedData[] vendorData)1138 public void onMatchWithDistance(int peerId, byte[] serviceSpecificInfo, byte[] matchFilter, 1139 int distanceMm, int peerCipherSuite, byte[] scid, String pairingAlias, 1140 AwarePairingConfig pairingConfig, @Nullable OuiKeyedData[] vendorData) { 1141 if (VDBG) { 1142 Log.v(TAG, "onMatchWithDistance: peerId=" + peerId + ", distanceMm=" + distanceMm); 1143 } 1144 mHandler.post(() -> { 1145 List<byte[]> matchFilterList = getMatchFilterList(matchFilter); 1146 mOriginalCallback.onServiceDiscoveredWithinRange( 1147 new PeerHandle(peerId), 1148 serviceSpecificInfo, 1149 matchFilterList, distanceMm); 1150 mOriginalCallback.onServiceDiscoveredWithinRange( 1151 new ServiceDiscoveryInfo( 1152 new PeerHandle(peerId), 1153 peerCipherSuite, 1154 serviceSpecificInfo, 1155 matchFilterList, 1156 scid, 1157 pairingAlias, 1158 pairingConfig, 1159 vendorData), 1160 distanceMm); 1161 }); 1162 } 1163 @Override onMatchExpired(int peerId)1164 public void onMatchExpired(int peerId) { 1165 if (VDBG) { 1166 Log.v(TAG, "onMatchExpired: peerId=" + peerId); 1167 } 1168 mHandler.post(() -> 1169 mOriginalCallback.onServiceLost(new PeerHandle(peerId), 1170 WIFI_AWARE_DISCOVERY_LOST_REASON_PEER_NOT_VISIBLE)); 1171 } 1172 1173 @Override onMessageSendSuccess(int messageId)1174 public void onMessageSendSuccess(int messageId) { 1175 if (VDBG) Log.v(TAG, "onMessageSendSuccess"); 1176 mHandler.post(() -> mOriginalCallback.onMessageSendSucceeded(messageId)); 1177 } 1178 1179 @Override onMessageSendFail(int messageId, int reason)1180 public void onMessageSendFail(int messageId, int reason) { 1181 if (VDBG) Log.v(TAG, "onMessageSendFail: reason=" + reason); 1182 mHandler.post(() -> mOriginalCallback.onMessageSendFailed(messageId)); 1183 } 1184 1185 @Override onMessageReceived(int peerId, byte[] message)1186 public void onMessageReceived(int peerId, byte[] message) { 1187 if (VDBG) { 1188 Log.v(TAG, "onMessageReceived: peerId=" + peerId); 1189 } 1190 mHandler.post(() -> mOriginalCallback.onMessageReceived(new PeerHandle(peerId), 1191 message)); 1192 } 1193 1194 @Override onPairingSetupRequestReceived(int peerId, int requestId)1195 public void onPairingSetupRequestReceived(int peerId, int requestId) { 1196 mHandler.post(() -> 1197 mOriginalCallback.onPairingSetupRequestReceived(new PeerHandle(peerId), 1198 requestId)); 1199 } 1200 @Override onPairingSetupConfirmed(int peerId, boolean accept, String alias)1201 public void onPairingSetupConfirmed(int peerId, boolean accept, String alias) { 1202 if (accept) { 1203 mHandler.post(() -> mOriginalCallback 1204 .onPairingSetupSucceeded(new PeerHandle(peerId), alias)); 1205 } else { 1206 mHandler.post(() -> mOriginalCallback 1207 .onPairingSetupFailed(new PeerHandle(peerId))); 1208 } 1209 } 1210 @Override onPairingVerificationConfirmed(int peerId, boolean accept, String alias)1211 public void onPairingVerificationConfirmed(int peerId, boolean accept, String alias) { 1212 if (accept) { 1213 mHandler.post(() -> mOriginalCallback.onPairingVerificationSucceed( 1214 new PeerHandle(peerId), alias)); 1215 } else { 1216 mHandler.post(() -> mOriginalCallback 1217 .onPairingVerificationFailed(new PeerHandle(peerId))); 1218 } 1219 } 1220 @Override onBootstrappingVerificationConfirmed(int peerId, boolean accept, int method)1221 public void onBootstrappingVerificationConfirmed(int peerId, boolean accept, int method) { 1222 if (accept) { 1223 mHandler.post(() -> mOriginalCallback.onBootstrappingSucceeded( 1224 new PeerHandle(peerId), method)); 1225 } else { 1226 mHandler.post(() -> mOriginalCallback.onBootstrappingFailed( 1227 new PeerHandle(peerId))); 1228 } 1229 } 1230 1231 @Override onRangingResultsReceived(List<RangingResult> rangingResults)1232 public void onRangingResultsReceived(List<RangingResult> rangingResults) { 1233 mHandler.post(() -> mOriginalCallback.onRangingResultsReceived(rangingResults)); 1234 } 1235 1236 /* 1237 * Proxies methods 1238 */ onProxySessionStarted(int sessionId)1239 public void onProxySessionStarted(int sessionId) { 1240 if (VDBG) Log.v(TAG, "Proxy: onSessionStarted: sessionId=" + sessionId); 1241 if (mSession != null) { 1242 Log.e(TAG, 1243 "onSessionStarted: sessionId=" + sessionId + ": session already created!?"); 1244 throw new IllegalStateException( 1245 "onSessionStarted: sessionId=" + sessionId + ": session already created!?"); 1246 } 1247 1248 WifiAwareManager mgr = mAwareManager.get(); 1249 if (mgr == null) { 1250 Log.w(TAG, "onProxySessionStarted: mgr GC'd"); 1251 return; 1252 } 1253 1254 if (mIsPublish) { 1255 PublishDiscoverySession session = new PublishDiscoverySession(mgr, 1256 mClientId, sessionId); 1257 mSession = session; 1258 mOriginalCallback.onPublishStarted(session); 1259 } else { 1260 SubscribeDiscoverySession 1261 session = new SubscribeDiscoverySession(mgr, mClientId, sessionId); 1262 mSession = session; 1263 mOriginalCallback.onSubscribeStarted(session); 1264 } 1265 } 1266 onProxySessionTerminated(int reason)1267 public void onProxySessionTerminated(int reason) { 1268 if (VDBG) Log.v(TAG, "Proxy: onSessionTerminated: reason=" + reason); 1269 if (mSession != null) { 1270 mSession.setTerminated(); 1271 mSession = null; 1272 } else { 1273 Log.w(TAG, "Proxy: onSessionTerminated called but mSession is null!?"); 1274 } 1275 mAwareManager.clear(); 1276 mOriginalCallback.onSessionTerminated(); 1277 } 1278 } 1279 1280 /** 1281 * Set Wi-Fi Aware protocol parameters. 1282 * @hide 1283 * @param params An object contain specified parameters. Use {@code null} to remove previously 1284 * set configuration and restore default behavior. 1285 */ 1286 @SystemApi 1287 @RequiresPermission(allOf = {OVERRIDE_WIFI_CONFIG, 1288 CHANGE_WIFI_STATE}) setAwareParams(@ullable AwareParams params)1289 public void setAwareParams(@Nullable AwareParams params) { 1290 try { 1291 mService.setAwareParams(params); 1292 } catch (RemoteException e) { 1293 throw e.rethrowFromSystemServer(); 1294 } 1295 } 1296 1297 /** 1298 * Set all Wi-Fi Aware sessions created by the calling app to be opportunistic. Opportunistic 1299 * Wi-Fi Aware sessions are considered low priority and may be torn down (the sessions or the 1300 * Aware interface) if there are resource conflicts. 1301 * 1302 * @param enabled True to configure all Wi-Fi Aware sessions by the calling app as 1303 * Opportunistic. False by default. 1304 */ 1305 @RequiresPermission(CHANGE_WIFI_STATE) setOpportunisticModeEnabled(boolean enabled)1306 public void setOpportunisticModeEnabled(boolean enabled) { 1307 try { 1308 mService.setOpportunisticModeEnabled(mContext.getOpPackageName(), enabled); 1309 } catch (RemoteException e) { 1310 throw e.rethrowFromSystemServer(); 1311 } 1312 } 1313 1314 /** 1315 * Indicate whether all Wi-Fi Aware sessions created by the calling app are opportunistic as 1316 * defined and configured by {@link #setOpportunisticModeEnabled(boolean)} 1317 * 1318 * @param executor The executor on which callback will be invoked. 1319 * @param resultsCallback An asynchronous callback that will return boolean 1320 */ 1321 @RequiresPermission(ACCESS_WIFI_STATE) isOpportunisticModeEnabled(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)1322 public void isOpportunisticModeEnabled(@NonNull @CallbackExecutor Executor executor, 1323 @NonNull Consumer<Boolean> resultsCallback) { 1324 Objects.requireNonNull(executor, "executor cannot be null"); 1325 Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null"); 1326 1327 try { 1328 mService.isOpportunisticModeEnabled(mContext.getOpPackageName(), 1329 new IBooleanListener.Stub() { 1330 @Override 1331 public void onResult(boolean value) { 1332 Binder.clearCallingIdentity(); 1333 executor.execute(() -> { 1334 resultsCallback.accept(value); 1335 }); 1336 } 1337 }); 1338 } catch (RemoteException e) { 1339 throw e.rethrowFromSystemServer(); 1340 } 1341 } 1342 1343 /** 1344 * Reset all paired devices setup by the caller by 1345 * {@link DiscoverySession#initiatePairingRequest(PeerHandle, String, int, String)} and 1346 * {@link DiscoverySession#acceptPairingRequest(int, PeerHandle, String, int, String)} 1347 */ 1348 @RequiresPermission(CHANGE_WIFI_STATE) resetPairedDevices()1349 public void resetPairedDevices() { 1350 try { 1351 mService.resetPairedDevices(mContext.getOpPackageName()); 1352 } catch (RemoteException e) { 1353 throw e.rethrowFromSystemServer(); 1354 } 1355 } 1356 1357 /** 1358 * Remove the target paired device setup by the caller by 1359 * {@link DiscoverySession#initiatePairingRequest(PeerHandle, String, int, String)} and 1360 * {@link DiscoverySession#acceptPairingRequest(int, PeerHandle, String, int, String)} 1361 * @param alias The alias set by the caller 1362 */ 1363 @RequiresPermission(CHANGE_WIFI_STATE) removePairedDevice(@onNull String alias)1364 public void removePairedDevice(@NonNull String alias) { 1365 try { 1366 mService.removePairedDevice(mContext.getOpPackageName(), alias); 1367 } catch (RemoteException e) { 1368 throw e.rethrowFromSystemServer(); 1369 } 1370 } 1371 1372 /** 1373 * Get all the paired devices configured by the calling app. 1374 * @param executor The executor on which callback will be invoked. 1375 * @param resultsCallback An asynchronous callback that will return a list of paired devices' 1376 * alias 1377 */ 1378 @RequiresPermission(ACCESS_WIFI_STATE) getPairedDevices(@onNull Executor executor, @NonNull Consumer<List<String>> resultsCallback)1379 public void getPairedDevices(@NonNull Executor executor, 1380 @NonNull Consumer<List<String>> resultsCallback) { 1381 Objects.requireNonNull(executor, "executor cannot be null"); 1382 Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null"); 1383 try { 1384 mService.getPairedDevices( 1385 mContext.getOpPackageName(), 1386 new IListListener.Stub() { 1387 public void onResult(List value) { 1388 Binder.clearCallingIdentity(); 1389 executor.execute(() -> resultsCallback.accept(value)); 1390 } 1391 }); 1392 } catch (RemoteException e) { 1393 throw e.rethrowFromSystemServer(); 1394 } 1395 } 1396 1397 /** 1398 * @hide 1399 */ suspend(int clientId, int sessionId)1400 public void suspend(int clientId, int sessionId) { 1401 try { 1402 mService.suspend(clientId, sessionId); 1403 } catch (RemoteException e) { 1404 throw e.rethrowFromSystemServer(); 1405 } 1406 } 1407 1408 /** 1409 * @hide 1410 */ resume(int clientId, int sessionId)1411 public void resume(int clientId, int sessionId) { 1412 try { 1413 mService.resume(clientId, sessionId); 1414 } catch (RemoteException e) { 1415 throw e.rethrowFromSystemServer(); 1416 } 1417 } 1418 /** 1419 * Attach to the Wi-Fi Aware service as an offload session. All discovery sessions and 1420 * connections will be handled via out-of-band connections. 1421 * The Aware session created by this attach method will have the lowest priority when resource 1422 * conflicts arise (e.g. Aware has to be torn down to create other WiFi interfaces). 1423 * 1424 * @param executor The executor to execute the listener of the {@code attachCallback} 1425 * object. 1426 * @param attachCallback A callback for attach events, extended from 1427 * {@link AttachCallback}. 1428 * @hide 1429 * @see #attach(AttachCallback, Handler) 1430 */ 1431 @SystemApi 1432 @RequiresPermission(allOf = {ACCESS_WIFI_STATE, CHANGE_WIFI_STATE, OVERRIDE_WIFI_CONFIG}) attachOffload(@onNull @allbackExecutor Executor executor, @NonNull AttachCallback attachCallback)1433 public void attachOffload(@NonNull @CallbackExecutor Executor executor, 1434 @NonNull AttachCallback attachCallback) { 1435 if (executor == null) { 1436 throw new IllegalArgumentException("Null executor provided"); 1437 } 1438 attach(null, null, attachCallback, null, true, executor); 1439 } 1440 1441 } 1442