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.MANAGE_WIFI_NETWORK_SELECTION; 20 21 import static com.android.ranging.flags.Flags.FLAG_RANGING_RTT_ENABLED; 22 23 import android.annotation.FlaggedApi; 24 import android.annotation.IntDef; 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.annotation.RequiresPermission; 28 import android.annotation.SystemApi; 29 import android.net.wifi.OuiKeyedData; 30 import android.net.wifi.ParcelUtil; 31 import android.net.wifi.ScanResult; 32 import android.net.wifi.WifiScanner; 33 import android.net.wifi.util.HexEncoding; 34 import android.os.Build; 35 import android.os.Parcel; 36 import android.os.Parcelable; 37 38 import androidx.annotation.RequiresApi; 39 40 import com.android.modules.utils.build.SdkLevel; 41 import com.android.wifi.flags.Flags; 42 43 import java.lang.annotation.Retention; 44 import java.lang.annotation.RetentionPolicy; 45 import java.nio.charset.StandardCharsets; 46 import java.util.Arrays; 47 import java.util.Collections; 48 import java.util.List; 49 import java.util.Objects; 50 51 /** 52 * Defines the configuration of an Aware publish session. Built using 53 * {@link PublishConfig.Builder}. A publish session is created using 54 * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback, 55 * android.os.Handler)} or updated using 56 * {@link PublishDiscoverySession#updatePublish(PublishConfig)}. 57 */ 58 public final class PublishConfig implements Parcelable { 59 /** @hide */ 60 @IntDef({ 61 PUBLISH_TYPE_UNSOLICITED, PUBLISH_TYPE_SOLICITED }) 62 @Retention(RetentionPolicy.SOURCE) 63 public @interface PublishTypes { 64 } 65 66 /** 67 * Defines an unsolicited publish session - a publish session where the publisher is 68 * advertising itself by broadcasting on-the-air. An unsolicited publish session is paired 69 * with a passive subscribe session {@link SubscribeConfig#SUBSCRIBE_TYPE_PASSIVE}. 70 * Configuration is done using {@link PublishConfig.Builder#setPublishType(int)}. 71 */ 72 public static final int PUBLISH_TYPE_UNSOLICITED = 0; 73 74 /** 75 * Defines a solicited publish session - a publish session which is silent, waiting for a 76 * matching active subscribe session - and responding to it in unicast. A 77 * solicited publish session is paired with an active subscribe session 78 * {@link SubscribeConfig#SUBSCRIBE_TYPE_ACTIVE}. Configuration is done using 79 * {@link PublishConfig.Builder#setPublishType(int)}. 80 */ 81 public static final int PUBLISH_TYPE_SOLICITED = 1; 82 83 /** @hide */ 84 public final byte[] mServiceName; 85 86 /** @hide */ 87 public final byte[] mServiceSpecificInfo; 88 89 /** @hide */ 90 public final byte[] mMatchFilter; 91 92 /** @hide */ 93 public final int mPublishType; 94 95 /** @hide */ 96 public final int mTtlSec; 97 98 /** @hide */ 99 public final boolean mEnableTerminateNotification; 100 101 /** @hide */ 102 public final boolean mEnableRanging; 103 104 private final boolean mEnableInstantMode; 105 106 private final int mBand; 107 108 private final WifiAwareDataPathSecurityConfig mSecurityConfig; 109 110 private final AwarePairingConfig mPairingConfig; 111 112 private final boolean mIsSuspendable; 113 114 private final List<OuiKeyedData> mVendorData; 115 116 /** @hide */ 117 public final boolean mEnablePeriodicRangingResults; 118 119 /** @hide */ PublishConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter, int publishType, int ttlSec, boolean enableTerminateNotification, boolean enableRanging, boolean enableInstantMode, @WifiScanner.WifiBand int band, WifiAwareDataPathSecurityConfig securityConfig, AwarePairingConfig pairingConfig, boolean isSuspendable, @NonNull List<OuiKeyedData> vendorData, boolean enablePeriodicRangingResults)120 public PublishConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter, 121 int publishType, int ttlSec, boolean enableTerminateNotification, 122 boolean enableRanging, boolean enableInstantMode, @WifiScanner.WifiBand int 123 band, WifiAwareDataPathSecurityConfig securityConfig, 124 AwarePairingConfig pairingConfig, boolean isSuspendable, 125 @NonNull List<OuiKeyedData> vendorData, boolean enablePeriodicRangingResults) { 126 mServiceName = serviceName; 127 mServiceSpecificInfo = serviceSpecificInfo; 128 mMatchFilter = matchFilter; 129 mPublishType = publishType; 130 mTtlSec = ttlSec; 131 mEnableTerminateNotification = enableTerminateNotification; 132 mEnableRanging = enableRanging; 133 mEnableInstantMode = enableInstantMode; 134 mBand = band; 135 mSecurityConfig = securityConfig; 136 mPairingConfig = pairingConfig; 137 mIsSuspendable = isSuspendable; 138 mVendorData = vendorData; 139 mEnablePeriodicRangingResults = enablePeriodicRangingResults; 140 } 141 142 @Override toString()143 public String toString() { 144 return "PublishConfig [mServiceName='" + (mServiceName == null ? "<null>" : String.valueOf( 145 HexEncoding.encode(mServiceName))) + ", mServiceName.length=" + ( 146 mServiceName == null ? 0 : mServiceName.length) + ", mServiceSpecificInfo='" + ( 147 (mServiceSpecificInfo == null) ? "<null>" : String.valueOf( 148 HexEncoding.encode(mServiceSpecificInfo))) 149 + ", mServiceSpecificInfo.length=" + (mServiceSpecificInfo == null ? 0 150 : mServiceSpecificInfo.length) + ", mMatchFilter=" 151 + (new TlvBufferUtils.TlvIterable(0, 1, mMatchFilter)).toString() 152 + ", mMatchFilter.length=" + (mMatchFilter == null ? 0 : mMatchFilter.length) 153 + ", mPublishType=" + mPublishType + ", mTtlSec=" + mTtlSec 154 + ", mEnableTerminateNotification=" + mEnableTerminateNotification 155 + ", mEnableRanging=" + mEnableRanging + "]" 156 + ", mEnableInstantMode=" + mEnableInstantMode 157 + ", mBand=" + mBand 158 + ", mSecurityConfig" + mSecurityConfig 159 + ", mPairingConfig" + mPairingConfig 160 + ", mIsSuspendable=" + mIsSuspendable 161 + ", mVendorData=" + mVendorData + "]" 162 + ", mEnablePeriodicRangingResults=" + mEnablePeriodicRangingResults; 163 } 164 165 @Override describeContents()166 public int describeContents() { 167 return 0; 168 } 169 170 @Override writeToParcel(Parcel dest, int flags)171 public void writeToParcel(Parcel dest, int flags) { 172 dest.writeByteArray(mServiceName); 173 dest.writeByteArray(mServiceSpecificInfo); 174 dest.writeByteArray(mMatchFilter); 175 dest.writeInt(mPublishType); 176 dest.writeInt(mTtlSec); 177 dest.writeInt(mEnableTerminateNotification ? 1 : 0); 178 dest.writeInt(mEnableRanging ? 1 : 0); 179 dest.writeBoolean(mEnableInstantMode); 180 dest.writeInt(mBand); 181 dest.writeParcelable(mSecurityConfig, flags); 182 dest.writeParcelable(mPairingConfig, flags); 183 dest.writeBoolean(mIsSuspendable); 184 dest.writeList(mVendorData); 185 dest.writeBoolean(mEnablePeriodicRangingResults); 186 } 187 188 @NonNull 189 public static final Creator<PublishConfig> CREATOR = new Creator<>() { 190 @Override 191 public PublishConfig[] newArray(int size) { 192 return new PublishConfig[size]; 193 } 194 195 @Override 196 public PublishConfig createFromParcel(Parcel in) { 197 byte[] serviceName = in.createByteArray(); 198 byte[] ssi = in.createByteArray(); 199 byte[] matchFilter = in.createByteArray(); 200 int publishType = in.readInt(); 201 int ttlSec = in.readInt(); 202 boolean enableTerminateNotification = in.readInt() != 0; 203 boolean enableRanging = in.readInt() != 0; 204 boolean enableInstantMode = in.readBoolean(); 205 int band = in.readInt(); 206 WifiAwareDataPathSecurityConfig securityConfig = in 207 .readParcelable(WifiAwareDataPathSecurityConfig.class.getClassLoader()); 208 AwarePairingConfig pairingConfig = in 209 .readParcelable(AwarePairingConfig.class.getClassLoader()); 210 boolean isSuspendable = in.readBoolean(); 211 List<OuiKeyedData> vendorData = ParcelUtil.readOuiKeyedDataList(in); 212 boolean enablePeriodicRangingResults = in.readBoolean(); 213 214 return new PublishConfig(serviceName, ssi, matchFilter, publishType, ttlSec, 215 enableTerminateNotification, enableRanging, enableInstantMode, 216 band, securityConfig, pairingConfig, isSuspendable, vendorData, 217 enablePeriodicRangingResults); 218 } 219 }; 220 221 @Override equals(Object o)222 public boolean equals(Object o) { 223 if (this == o) { 224 return true; 225 } 226 227 if (!(o instanceof PublishConfig)) { 228 return false; 229 } 230 231 PublishConfig lhs = (PublishConfig) o; 232 233 return Arrays.equals(mServiceName, lhs.mServiceName) && Arrays.equals(mServiceSpecificInfo, 234 lhs.mServiceSpecificInfo) && Arrays.equals(mMatchFilter, lhs.mMatchFilter) 235 && mPublishType == lhs.mPublishType 236 && mTtlSec == lhs.mTtlSec 237 && mEnableTerminateNotification == lhs.mEnableTerminateNotification 238 && mEnableRanging == lhs.mEnableRanging 239 && mEnablePeriodicRangingResults == lhs.mEnablePeriodicRangingResults 240 && mEnableInstantMode == lhs.mEnableInstantMode 241 && mBand == lhs.mBand 242 && mIsSuspendable == lhs.mIsSuspendable 243 && Objects.equals(mSecurityConfig, lhs.mSecurityConfig) 244 && Objects.equals(mPairingConfig, lhs.mPairingConfig) 245 && Objects.equals(mVendorData, lhs.mVendorData); 246 } 247 248 @Override hashCode()249 public int hashCode() { 250 return Objects.hash(Arrays.hashCode(mServiceName), Arrays.hashCode(mServiceSpecificInfo), 251 Arrays.hashCode(mMatchFilter), mPublishType, mTtlSec, mEnableTerminateNotification, 252 mEnableRanging, mEnableInstantMode, mBand, mSecurityConfig, mPairingConfig, 253 mIsSuspendable, mVendorData, mEnablePeriodicRangingResults); 254 } 255 256 /** 257 * Verifies that the contents of the PublishConfig are valid. Otherwise 258 * throws an IllegalArgumentException. 259 * 260 * @hide 261 */ assertValid(Characteristics characteristics, boolean rttSupported)262 public void assertValid(Characteristics characteristics, boolean rttSupported) 263 throws IllegalArgumentException { 264 WifiAwareUtils.validateServiceName(mServiceName); 265 266 if (!TlvBufferUtils.isValid(mMatchFilter, 0, 1)) { 267 throw new IllegalArgumentException( 268 "Invalid txFilter configuration - LV fields do not match up to length"); 269 } 270 if (mPublishType < PUBLISH_TYPE_UNSOLICITED || mPublishType > PUBLISH_TYPE_SOLICITED) { 271 throw new IllegalArgumentException("Invalid publishType - " + mPublishType); 272 } 273 if (mTtlSec < 0) { 274 throw new IllegalArgumentException("Invalid ttlSec - must be non-negative"); 275 } 276 if (mSecurityConfig != null && !mSecurityConfig.isValid()) { 277 throw new IllegalArgumentException("WifiAwareDataPathSecurityConfig is invalid"); 278 } 279 280 if (characteristics != null) { 281 int maxServiceNameLength = characteristics.getMaxServiceNameLength(); 282 if (maxServiceNameLength != 0 && mServiceName.length > maxServiceNameLength) { 283 throw new IllegalArgumentException( 284 "Service name longer than supported by device characteristics"); 285 } 286 int maxServiceSpecificInfoLength = characteristics.getMaxServiceSpecificInfoLength(); 287 if (maxServiceSpecificInfoLength != 0 && mServiceSpecificInfo != null 288 && mServiceSpecificInfo.length > maxServiceSpecificInfoLength) { 289 throw new IllegalArgumentException( 290 "Service specific info longer than supported by device characteristics"); 291 } 292 int maxMatchFilterLength = characteristics.getMaxMatchFilterLength(); 293 if (maxMatchFilterLength != 0 && mMatchFilter != null 294 && mMatchFilter.length > maxMatchFilterLength) { 295 throw new IllegalArgumentException( 296 "Match filter longer than supported by device characteristics"); 297 } 298 if (mEnableInstantMode) { 299 if (SdkLevel.isAtLeastT() 300 && characteristics.isInstantCommunicationModeSupported()) { 301 // Valid to use instant communication mode 302 } else { 303 throw new IllegalArgumentException("instant mode is not supported"); 304 } 305 } 306 if (mIsSuspendable && !characteristics.isSuspensionSupported()) { 307 throw new IllegalArgumentException("Aware Suspension is not supported"); 308 } 309 if (mSecurityConfig != null && (characteristics.getSupportedCipherSuites() 310 & mSecurityConfig.getCipherSuite()) == 0) { 311 throw new IllegalArgumentException("Unsupported cipher suite"); 312 } 313 if (mPairingConfig != null && !characteristics.isAwarePairingSupported()) { 314 throw new IllegalArgumentException("Aware Pairing is not supported"); 315 } 316 if (mPairingConfig != null && !mPairingConfig.assertValid(characteristics)) { 317 throw new IllegalArgumentException("Unsupported pairing config"); 318 } 319 } 320 321 if (!rttSupported && mEnableRanging) { 322 throw new IllegalArgumentException("Ranging is not supported"); 323 } 324 325 if ((!rttSupported || !characteristics.isPeriodicRangingSupported()) 326 && mEnablePeriodicRangingResults) { 327 throw new IllegalArgumentException("Periodic Ranging is not supported"); 328 } 329 } 330 331 /** 332 * Check if instant communication mode is enabled for this publish session. 333 * @see Builder#setInstantCommunicationModeEnabled(boolean, int) 334 * @return true for enabled, false otherwise. 335 */ isInstantCommunicationModeEnabled()336 public boolean isInstantCommunicationModeEnabled() { 337 return mEnableInstantMode; 338 } 339 340 /** 341 * Get the Wi-Fi band for instant communication mode for this publish session 342 * 343 * @see Builder#setInstantCommunicationModeEnabled(boolean, int) 344 * @return The Wi-Fi band. If instant communication mode is not enabled will return {@link 345 * ScanResult#WIFI_BAND_24_GHZ} as default. 346 */ 347 @WifiAwareManager.InstantModeBand getInstantCommunicationBand()348 public int getInstantCommunicationBand() { 349 return mBand; 350 } 351 352 /** 353 * Get the data-path security config for this publish session 354 * @see Builder#setDataPathSecurityConfig(WifiAwareDataPathSecurityConfig) 355 * @return A {@link WifiAwareDataPathSecurityConfig} specified in this config. 356 */ 357 @Nullable getSecurityConfig()358 public WifiAwareDataPathSecurityConfig getSecurityConfig() { 359 return mSecurityConfig; 360 } 361 362 /** 363 * Get the Aware Pairing config for this publish session 364 * @see Builder#setPairingConfig(AwarePairingConfig) 365 * @return A {@link AwarePairingConfig} specified in this config. 366 */ 367 @Nullable getPairingConfig()368 public AwarePairingConfig getPairingConfig() { 369 return mPairingConfig; 370 } 371 372 /** 373 * Check if suspension is supported for this publish session. 374 * @see Builder#setSuspendable(boolean) 375 * @return true for supported, false otherwise. 376 * @hide 377 */ 378 @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 379 @SystemApi isSuspendable()380 public boolean isSuspendable() { 381 if (!SdkLevel.isAtLeastU()) { 382 throw new UnsupportedOperationException(); 383 } 384 return mIsSuspendable; 385 } 386 387 /** 388 * Return the vendor-provided configuration data, if it exists. See also {@link 389 * Builder#setVendorData(List)} 390 * 391 * @return Vendor configuration data, or empty list if it does not exist. 392 * @hide 393 */ 394 @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) 395 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) 396 @NonNull 397 @SystemApi getVendorData()398 public List<OuiKeyedData> getVendorData() { 399 if (!SdkLevel.isAtLeastV()) { 400 throw new UnsupportedOperationException(); 401 } 402 return mVendorData != null ? mVendorData : Collections.emptyList(); 403 } 404 405 /** 406 * Check if periodic ranging reporting is enabled for publish session 407 * @see Builder#setPeriodicRangingResultsEnabled(boolean) 408 * @return true for enabled, false otherwise. 409 * @hide 410 */ 411 @FlaggedApi(FLAG_RANGING_RTT_ENABLED) 412 @SystemApi isPeriodicRangingResultsEnabled()413 public boolean isPeriodicRangingResultsEnabled() { 414 return mEnablePeriodicRangingResults; 415 } 416 417 /** 418 * Builder used to build {@link PublishConfig} objects. 419 */ 420 public static final class Builder { 421 private byte[] mServiceName; 422 private byte[] mServiceSpecificInfo; 423 private byte[] mMatchFilter; 424 private int mPublishType = PUBLISH_TYPE_UNSOLICITED; 425 private int mTtlSec = 0; 426 private boolean mEnableTerminateNotification = true; 427 private boolean mEnableRanging = false; 428 private boolean mEnableInstantMode = false; 429 private int mBand = WifiScanner.WIFI_BAND_24_GHZ; 430 private WifiAwareDataPathSecurityConfig mSecurityConfig = null; 431 private AwarePairingConfig mPairingConfig = null; 432 private boolean mIsSuspendable = false; 433 private @NonNull List<OuiKeyedData> mVendorData = Collections.emptyList(); 434 private boolean mEnablePeriodicRangingResults = false; 435 436 /** 437 * Specify the service name of the publish session. The actual on-air 438 * value is a 6 byte hashed representation of this string. 439 * <p> 440 * The Service Name is a UTF-8 encoded string from 1 to 255 bytes in length. 441 * The only acceptable single-byte UTF-8 symbols for a Service Name are alphanumeric 442 * values (A-Z, a-z, 0-9), the hyphen ('-'), the period ('.') and the underscore ('_'). All 443 * valid multi-byte UTF-8 characters are acceptable in a Service Name. 444 * <p> 445 * Note: for compatibility with devices running Android 11 or older, avoid using 446 * underscore ('_') symbol as a single-byte UTF-8 service name. 447 * <p> 448 * Must be called - an empty ServiceName is not valid. 449 * 450 * @param serviceName The service name for the publish session. 451 * 452 * @return The builder to facilitate chaining 453 * {@code builder.setXXX(..).setXXX(..)}. 454 */ setServiceName(@onNull String serviceName)455 public Builder setServiceName(@NonNull String serviceName) { 456 if (serviceName == null) { 457 throw new IllegalArgumentException("Invalid service name - must be non-null"); 458 } 459 mServiceName = serviceName.getBytes(StandardCharsets.UTF_8); 460 return this; 461 } 462 463 /** 464 * Specify service specific information for the publish session. This is 465 * a free-form byte array available to the application to send 466 * additional information as part of the discovery operation - it 467 * will not be used to determine whether a publish/subscribe match 468 * occurs. 469 * <p> 470 * Optional. Empty by default. 471 * 472 * @param serviceSpecificInfo A byte-array for the service-specific 473 * information field. 474 * 475 * @return The builder to facilitate chaining 476 * {@code builder.setXXX(..).setXXX(..)}. 477 */ setServiceSpecificInfo(@ullable byte[] serviceSpecificInfo)478 public Builder setServiceSpecificInfo(@Nullable byte[] serviceSpecificInfo) { 479 mServiceSpecificInfo = serviceSpecificInfo; 480 return this; 481 } 482 483 /** 484 * The match filter for a publish session. Used to determine whether a service 485 * discovery occurred - in addition to relying on the service name. 486 * <p> 487 * Optional. Empty by default. 488 * 489 * @param matchFilter A list of match filter entries (each of which is an arbitrary byte 490 * array). 491 * 492 * @return The builder to facilitate chaining 493 * {@code builder.setXXX(..).setXXX(..)}. 494 */ setMatchFilter(@ullable List<byte[]> matchFilter)495 public Builder setMatchFilter(@Nullable List<byte[]> matchFilter) { 496 mMatchFilter = new TlvBufferUtils.TlvConstructor(0, 1).allocateAndPut( 497 matchFilter).getArray(); 498 return this; 499 } 500 501 /** 502 * Specify the type of the publish session: solicited (aka active - publish 503 * packets are transmitted over-the-air), or unsolicited (aka passive - 504 * no publish packets are transmitted, a match is made against an active 505 * subscribe session whose packets are transmitted over-the-air). 506 * 507 * @param publishType Publish session type: 508 * {@link PublishConfig#PUBLISH_TYPE_SOLICITED} or 509 * {@link PublishConfig#PUBLISH_TYPE_UNSOLICITED} (the default). 510 * 511 * @return The builder to facilitate chaining 512 * {@code builder.setXXX(..).setXXX(..)}. 513 */ setPublishType(@ublishTypes int publishType)514 public Builder setPublishType(@PublishTypes int publishType) { 515 if (publishType < PUBLISH_TYPE_UNSOLICITED || publishType > PUBLISH_TYPE_SOLICITED) { 516 throw new IllegalArgumentException("Invalid publishType - " + publishType); 517 } 518 mPublishType = publishType; 519 return this; 520 } 521 522 /** 523 * Sets the time interval (in seconds) an unsolicited ( 524 * {@link PublishConfig.Builder#setPublishType(int)}) publish session 525 * will be alive - broadcasting a packet. When the TTL is reached 526 * an event will be generated for 527 * {@link DiscoverySessionCallback#onSessionTerminated()} [unless 528 * {@link #setTerminateNotificationEnabled(boolean)} disables the callback]. 529 * <p> 530 * Optional. 0 by default - indicating the session doesn't terminate on its own. 531 * Session will be terminated when {@link DiscoverySession#close()} is 532 * called. 533 * 534 * @param ttlSec Lifetime of a publish session in seconds. 535 * 536 * @return The builder to facilitate chaining 537 * {@code builder.setXXX(..).setXXX(..)}. 538 */ setTtlSec(int ttlSec)539 public Builder setTtlSec(int ttlSec) { 540 if (ttlSec < 0) { 541 throw new IllegalArgumentException("Invalid ttlSec - must be non-negative"); 542 } 543 mTtlSec = ttlSec; 544 return this; 545 } 546 547 /** 548 * Configure whether a publish terminate notification 549 * {@link DiscoverySessionCallback#onSessionTerminated()} is reported 550 * back to the callback. 551 * 552 * @param enable If true the terminate callback will be called when the 553 * publish is terminated. Otherwise it will not be called. 554 * 555 * @return The builder to facilitate chaining 556 * {@code builder.setXXX(..).setXXX(..)}. 557 */ setTerminateNotificationEnabled(boolean enable)558 public Builder setTerminateNotificationEnabled(boolean enable) { 559 mEnableTerminateNotification = enable; 560 return this; 561 } 562 563 /** 564 * Configure whether the publish discovery session supports ranging and allows peers to 565 * measure distance to it. This API is used in conjunction with 566 * {@link SubscribeConfig.Builder#setMinDistanceMm(int)} and 567 * {@link SubscribeConfig.Builder#setMaxDistanceMm(int)} to specify a minimum and/or 568 * maximum distance at which discovery will be triggered. 569 * <p> 570 * Optional. Disabled by default - i.e. any peer attempt to measure distance to this device 571 * will be refused and discovery will proceed without ranging constraints. 572 * <p> 573 * The device must support Wi-Fi RTT for this feature to be used. Feature support is checked 574 * as described in {@link android.net.wifi.rtt}. 575 * 576 * @param enable If true, ranging is supported on request of the peer. 577 * 578 * @return The builder to facilitate chaining 579 * {@code builder.setXXX(..).setXXX(..)}. 580 */ setRangingEnabled(boolean enable)581 public Builder setRangingEnabled(boolean enable) { 582 mEnableRanging = enable; 583 return this; 584 } 585 586 /** 587 * Configure whether periodic ranging results need to be notified to Publisher 588 * <p> 589 * Optional. Disabled by default - i.e. any ranging result will not be notified to 590 * the Publisher. 591 * <p> 592 * The device must support Periodic Ranging for this feature to be used. 593 * Feature support check is determined by 594 * {@link Characteristics#isPeriodicRangingSupported()}. 595 * <p> 596 * The ranging result will be notified to Publisher via 597 * {@link DiscoverySessionCallback#onRangingResultsReceived(RangingResults)}. 598 * 599 * @param enable If true, ranging result will be notified to Publisher. 600 * 601 * @return The builder to facilitate chaining 602 * {@code builder.setXXX(..).setXXX(..)}. 603 * @hide 604 */ 605 @FlaggedApi(FLAG_RANGING_RTT_ENABLED) 606 @SystemApi 607 @NonNull setPeriodicRangingResultsEnabled(boolean enable)608 public Builder setPeriodicRangingResultsEnabled(boolean enable) { 609 mEnablePeriodicRangingResults = enable; 610 return this; 611 } 612 613 /** 614 * Configure whether to enable and use instant communication for this publish session. 615 * Instant communication will speed up service discovery and any data-path set up as part of 616 * this session. Use {@link Characteristics#isInstantCommunicationModeSupported()} to check 617 * if the device supports this feature. 618 * 619 * <p>Note: due to increased power requirements of this mode - it will only remain enabled 620 * for 30 seconds from the time the discovery session is started. 621 * 622 * @param enabled true for enable instant communication mode, default is false. 623 * @param band When setting to {@link ScanResult#WIFI_BAND_5_GHZ}, device will try to enable 624 * instant communication mode on 5Ghz, but may fall back to 2.4Ghz due to regulatory 625 * requirements. 626 * @return the current {@link Builder} builder, enabling chaining of builder methods. 627 */ 628 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 629 @NonNull setInstantCommunicationModeEnabled( boolean enabled, @WifiAwareManager.InstantModeBand int band)630 public Builder setInstantCommunicationModeEnabled( 631 boolean enabled, @WifiAwareManager.InstantModeBand int band) { 632 if (!SdkLevel.isAtLeastT()) { 633 throw new UnsupportedOperationException(); 634 } 635 if (band != ScanResult.WIFI_BAND_24_GHZ && band != ScanResult.WIFI_BAND_5_GHZ) { 636 throw new IllegalArgumentException(); 637 } 638 mBand = band; 639 mEnableInstantMode = enabled; 640 return this; 641 } 642 643 /** 644 * Configure security config for the Wi-Fi Aware publish session. The security config set 645 * here must be the same as the one used to request Wi-Fi Aware data-path connection using 646 * {@link WifiAwareNetworkSpecifier.Builder#setDataPathSecurityConfig(WifiAwareDataPathSecurityConfig)}. 647 * This security config will create a security identifier (SCID) which contains a PMKID and 648 * transmitted in the publish message. The device which subscribe this session can get this 649 * info by {@link ServiceDiscoveryInfo#getScid()} 650 * This method is optional - if not called, then no security context identifier will be 651 * passed in the publish message, then no security context identifier will be provided in 652 * the {@link ServiceDiscoveryInfo} on the subscriber. Security can still be negotiated 653 * using out-of-band (OOB) mechanisms. 654 * 655 * @param securityConfig The (optional) security config to be used to create security 656 * context Identifier 657 * @return the current {@link Builder} builder, enabling chaining of builder methods. 658 */ 659 @NonNull setDataPathSecurityConfig( @onNull WifiAwareDataPathSecurityConfig securityConfig)660 public Builder setDataPathSecurityConfig( 661 @NonNull WifiAwareDataPathSecurityConfig securityConfig) { 662 if (securityConfig == null) { 663 throw new IllegalArgumentException("The WifiAwareDataPathSecurityConfig " 664 + "should be non-null"); 665 } 666 if (!securityConfig.isValid()) { 667 throw new IllegalArgumentException("The WifiAwareDataPathSecurityConfig " 668 + "is invalid"); 669 } 670 mSecurityConfig = securityConfig; 671 return this; 672 } 673 674 /** 675 * Set the {@link AwarePairingConfig} for this publish session, the peer can use this info 676 * to determine the config of the following bootstrapping, pairing setup/verification 677 * request. 678 * @see AwarePairingConfig 679 * @param config The pairing config set to the peer. Only valid when 680 * {@link Characteristics#isAwarePairingSupported()} is true. 681 * @return the current {@link Builder} builder, enabling chaining of builder methods. 682 */ 683 @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) setPairingConfig(@ullable AwarePairingConfig config)684 @NonNull public Builder setPairingConfig(@Nullable AwarePairingConfig config) { 685 if (!SdkLevel.isAtLeastU()) { 686 throw new UnsupportedOperationException(); 687 } 688 mPairingConfig = config; 689 return this; 690 } 691 692 /** 693 * Specify whether to configure the publish discovery session to be suspendable. This API 694 * doesn't suspend the session, it allows it to be suspended and resumed in the future using 695 * {@link DiscoverySession#suspend()} and {@link DiscoverySession#resume()} respectively. 696 * <p> 697 * Optional. Not suspendable by default. 698 * <p> 699 * The device must support Wi-Fi Aware suspension for a publish session to be 700 * suspendable. Feature support check is determined by 701 * {@link Characteristics#isSuspensionSupported()}. 702 * 703 * @param isSuspendable If true, then this publish session can be suspended. 704 * 705 * @return the current {@link Builder} builder, enabling chaining of builder methods. 706 * 707 * @see DiscoverySession#suspend() 708 * @see DiscoverySession#resume() 709 * @hide 710 */ 711 @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 712 @RequiresPermission(value = MANAGE_WIFI_NETWORK_SELECTION) 713 @SystemApi 714 @NonNull setSuspendable(boolean isSuspendable)715 public Builder setSuspendable(boolean isSuspendable) { 716 if (!SdkLevel.isAtLeastU()) { 717 throw new UnsupportedOperationException(); 718 } 719 mIsSuspendable = isSuspendable; 720 return this; 721 } 722 723 /** 724 * Set additional vendor-provided configuration data. 725 * 726 * @param vendorData List of {@link OuiKeyedData} containing the vendor-provided 727 * configuration data. Note that multiple elements with the same OUI are allowed. 728 * @return Builder for chaining. 729 * @hide 730 */ 731 @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) 732 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) 733 @NonNull 734 @SystemApi setVendorData(@onNull List<OuiKeyedData> vendorData)735 public Builder setVendorData(@NonNull List<OuiKeyedData> vendorData) { 736 if (!SdkLevel.isAtLeastV()) { 737 throw new UnsupportedOperationException(); 738 } 739 if (vendorData == null) { 740 throw new IllegalArgumentException("setVendorData received a null value"); 741 } 742 mVendorData = vendorData; 743 return this; 744 } 745 746 /** 747 * Build {@link PublishConfig} given the current requests made on the 748 * builder. 749 */ build()750 public PublishConfig build() { 751 return new PublishConfig(mServiceName, mServiceSpecificInfo, mMatchFilter, mPublishType, 752 mTtlSec, mEnableTerminateNotification, mEnableRanging, mEnableInstantMode, 753 mBand, mSecurityConfig, mPairingConfig, mIsSuspendable, mVendorData, 754 mEnablePeriodicRangingResults); 755 } 756 } 757 } 758