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