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