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 android.annotation.FlaggedApi; 20 import android.annotation.NonNull; 21 import android.annotation.RequiresApi; 22 import android.annotation.SystemApi; 23 import android.net.wifi.OuiKeyedData; 24 import android.net.wifi.ParcelUtil; 25 import android.os.Build; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 29 import com.android.modules.utils.build.SdkLevel; 30 import com.android.wifi.flags.Flags; 31 32 import java.util.Arrays; 33 import java.util.Collections; 34 import java.util.List; 35 import java.util.Objects; 36 37 /** 38 * Defines a request object to configure a Wi-Fi Aware network. Built using 39 * {@link ConfigRequest.Builder}. Configuration is requested using 40 * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)}. 41 * Note that the actual achieved configuration may be different from the 42 * requested configuration - since different applications may request different 43 * configurations. 44 * 45 * @hide 46 */ 47 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) 48 @SystemApi 49 public final class ConfigRequest implements Parcelable { 50 /** 51 * Lower range of possible cluster ID. 52 * @hide 53 */ 54 public static final int CLUSTER_ID_MIN = 0; 55 56 /** 57 * Upper range of possible cluster ID. 58 * @hide 59 */ 60 public static final int CLUSTER_ID_MAX = 0xFFFF; 61 62 /** 63 * Indices for configuration variables which are specified per band. 64 * @hide 65 */ 66 public static final int NAN_BAND_24GHZ = 0; 67 68 /** @hide */ 69 public static final int NAN_BAND_5GHZ = 1; 70 71 /** @hide */ 72 public static final int NAN_BAND_6GHZ = 2; 73 74 /** 75 * Magic values for Discovery Window (DW) interval configuration 76 * @hide 77 */ 78 public static final int DW_INTERVAL_NOT_INIT = -1; 79 80 /** @hide */ 81 public static final int DW_DISABLE = 0; // only valid for 5GHz 82 83 /** 84 * Indicates whether 5G band support is requested. 85 * @hide 86 */ 87 public final boolean mSupport5gBand; 88 89 /** 90 * Indicates whether 6G band support is requested. 91 * @hide 92 */ 93 public final boolean mSupport6gBand; 94 95 /** 96 * Specifies the desired master preference. 97 * @hide 98 */ 99 public int mMasterPreference; 100 101 /** 102 * Specifies the desired lower range of the cluster ID. Must be lower than 103 * {@link ConfigRequest#mClusterHigh}. 104 * @hide 105 */ 106 public final int mClusterLow; 107 108 /** 109 * Specifies the desired higher range of the cluster ID. Must be higher than 110 * {@link ConfigRequest#mClusterLow}. 111 * @hide 112 */ 113 public final int mClusterHigh; 114 115 /** 116 * Specifies the discovery window interval for the device on NAN_BAND_*. 117 * @hide 118 */ 119 public final int mDiscoveryWindowInterval[]; 120 121 /** 122 * List of {@link OuiKeyedData} providing vendor-specific configuration data. 123 */ 124 private final List<OuiKeyedData> mVendorData; 125 ConfigRequest(boolean support5gBand, boolean support6gBand, int masterPreference, int clusterLow, int clusterHigh, int[] discoveryWindowInterval, @NonNull List<OuiKeyedData> vendorData)126 private ConfigRequest(boolean support5gBand, boolean support6gBand, int masterPreference, 127 int clusterLow, int clusterHigh, int[] discoveryWindowInterval, 128 @NonNull List<OuiKeyedData> vendorData) { 129 mSupport5gBand = support5gBand; 130 mSupport6gBand = support6gBand; 131 mMasterPreference = masterPreference; 132 mClusterLow = clusterLow; 133 mClusterHigh = clusterHigh; 134 mDiscoveryWindowInterval = discoveryWindowInterval; 135 mVendorData = vendorData; 136 } 137 138 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) 139 @Override toString()140 public String toString() { 141 return "ConfigRequest [mSupport5gBand=" + mSupport5gBand 142 + ", mSupport6gBand=" + mSupport6gBand 143 + ", mMasterPreference=" + mMasterPreference 144 + ", mClusterLow=" + mClusterLow 145 + ", mClusterHigh=" + mClusterHigh 146 + ", mDiscoveryWindowInterval=" + Arrays.toString(mDiscoveryWindowInterval) 147 + ", mVendorData=" + mVendorData 148 + "]"; 149 } 150 151 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) 152 @Override describeContents()153 public int describeContents() { 154 return 0; 155 } 156 157 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) 158 @Override writeToParcel(@onNull Parcel dest, int flags)159 public void writeToParcel(@NonNull Parcel dest, int flags) { 160 dest.writeInt(mSupport5gBand ? 1 : 0); 161 dest.writeInt(mSupport6gBand ? 1 : 0); 162 dest.writeInt(mMasterPreference); 163 dest.writeInt(mClusterLow); 164 dest.writeInt(mClusterHigh); 165 dest.writeIntArray(mDiscoveryWindowInterval); 166 dest.writeList(mVendorData); 167 } 168 169 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) 170 public static final @android.annotation.NonNull Creator<ConfigRequest> CREATOR = new Creator<ConfigRequest>() { 171 @Override 172 public ConfigRequest[] newArray(int size) { 173 return new ConfigRequest[size]; 174 } 175 176 @Override 177 public ConfigRequest createFromParcel(Parcel in) { 178 boolean support5gBand = in.readInt() != 0; 179 boolean support6gBand = in.readInt() != 0; 180 int masterPreference = in.readInt(); 181 int clusterLow = in.readInt(); 182 int clusterHigh = in.readInt(); 183 int discoveryWindowInterval[] = in.createIntArray(); 184 List<OuiKeyedData> vendorData = ParcelUtil.readOuiKeyedDataList(in); 185 186 return new ConfigRequest(support5gBand, support6gBand, masterPreference, clusterLow, 187 clusterHigh, discoveryWindowInterval, vendorData); 188 } 189 }; 190 191 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) 192 @Override equals(Object o)193 public boolean equals(Object o) { 194 if (this == o) { 195 return true; 196 } 197 198 if (!(o instanceof ConfigRequest)) { 199 return false; 200 } 201 202 ConfigRequest lhs = (ConfigRequest) o; 203 204 return mSupport5gBand == lhs.mSupport5gBand 205 && mSupport6gBand == lhs.mSupport6gBand 206 && mMasterPreference == lhs.mMasterPreference 207 && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh 208 && Arrays.equals(mDiscoveryWindowInterval, lhs.mDiscoveryWindowInterval) 209 && Objects.equals(mVendorData, lhs.mVendorData); 210 } 211 212 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) 213 @Override hashCode()214 public int hashCode() { 215 int result = 17; 216 217 result = 31 * result + (mSupport5gBand ? 1 : 0); 218 result = 31 * result + (mSupport6gBand ? 1 : 0); 219 result = 31 * result + mMasterPreference; 220 result = 31 * result + mClusterLow; 221 result = 31 * result + mClusterHigh; 222 result = 31 * result + Arrays.hashCode(mDiscoveryWindowInterval); 223 result = 31 * result + mVendorData.hashCode(); 224 225 return result; 226 } 227 228 /** 229 * Verifies that the contents of the ConfigRequest are valid. Otherwise 230 * throws an IllegalArgumentException. 231 * @hide 232 */ validate()233 public void validate() throws IllegalArgumentException { 234 if (mMasterPreference < 0) { 235 throw new IllegalArgumentException( 236 "Master Preference specification must be non-negative"); 237 } 238 if (mMasterPreference == 1 || mMasterPreference == 255 || mMasterPreference > 255) { 239 throw new IllegalArgumentException("Master Preference specification must not " 240 + "exceed 255 or use 1 or 255 (reserved values)"); 241 } 242 if (mClusterLow < CLUSTER_ID_MIN) { 243 throw new IllegalArgumentException("Cluster specification must be non-negative"); 244 } 245 if (mClusterLow > CLUSTER_ID_MAX) { 246 throw new IllegalArgumentException("Cluster specification must not exceed 0xFFFF"); 247 } 248 if (mClusterHigh < CLUSTER_ID_MIN) { 249 throw new IllegalArgumentException("Cluster specification must be non-negative"); 250 } 251 if (mClusterHigh > CLUSTER_ID_MAX) { 252 throw new IllegalArgumentException("Cluster specification must not exceed 0xFFFF"); 253 } 254 if (mClusterLow > mClusterHigh) { 255 throw new IllegalArgumentException( 256 "Invalid argument combination - must have Cluster Low <= Cluster High"); 257 } 258 if (mDiscoveryWindowInterval.length != 3) { 259 throw new IllegalArgumentException( 260 "Invalid discovery window interval: must have 3 elements (2.4 & 5 & 6"); 261 } 262 if (mDiscoveryWindowInterval[NAN_BAND_24GHZ] != DW_INTERVAL_NOT_INIT && 263 (mDiscoveryWindowInterval[NAN_BAND_24GHZ] < 1 // valid for 2.4GHz: [1-5] 264 || mDiscoveryWindowInterval[NAN_BAND_24GHZ] > 5)) { 265 throw new IllegalArgumentException( 266 "Invalid discovery window interval for 2.4GHz: valid is UNSET or [1,5]"); 267 } 268 if (mDiscoveryWindowInterval[NAN_BAND_5GHZ] != DW_INTERVAL_NOT_INIT && 269 (mDiscoveryWindowInterval[NAN_BAND_5GHZ] < 0 // valid for 5GHz: [0-5] 270 || mDiscoveryWindowInterval[NAN_BAND_5GHZ] > 5)) { 271 throw new IllegalArgumentException( 272 "Invalid discovery window interval for 5GHz: valid is UNSET or [0,5]"); 273 } 274 if (mDiscoveryWindowInterval[NAN_BAND_6GHZ] != DW_INTERVAL_NOT_INIT 275 && (mDiscoveryWindowInterval[NAN_BAND_6GHZ] < 0 // valid for 6GHz: [0-5] 276 || mDiscoveryWindowInterval[NAN_BAND_6GHZ] > 5)) { 277 throw new IllegalArgumentException( 278 "Invalid discovery window interval for 6GHz: valid is UNSET or [0,5]"); 279 } 280 if (mVendorData == null) { 281 throw new IllegalArgumentException("Vendor data list must be non-null"); 282 } 283 } 284 285 /** 286 * Get the vendor-provided configuration data, if it exists. See {@link 287 * Builder#setVendorData(List)} 288 * 289 * @return Vendor configuration data, or empty list if it does not exist. 290 * @hide 291 */ 292 @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) 293 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) 294 @SystemApi 295 @NonNull getVendorData()296 public List<OuiKeyedData> getVendorData() { 297 if (!SdkLevel.isAtLeastV()) { 298 throw new UnsupportedOperationException(); 299 } 300 return mVendorData != null ? mVendorData : Collections.emptyList(); 301 } 302 303 /** 304 * Builder used to build {@link ConfigRequest} objects. 305 */ 306 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) 307 public static final class Builder { 308 private boolean mSupport5gBand = true; 309 private boolean mSupport6gBand = false; 310 private int mMasterPreference = 0; 311 private int mClusterLow = CLUSTER_ID_MIN; 312 private int mClusterHigh = CLUSTER_ID_MAX; 313 private int[] mDiscoveryWindowInterval = {DW_INTERVAL_NOT_INIT, DW_INTERVAL_NOT_INIT, 314 DW_INTERVAL_NOT_INIT}; 315 private List<OuiKeyedData> mVendorData = Collections.emptyList(); 316 317 /** 318 * Specify whether 5G band support is required in this request. Disabled by default. 319 * 320 * @param support5gBand Support for 5G band is required. 321 * 322 * @return The builder to facilitate chaining 323 * {@code builder.setXXX(..).setXXX(..)}. 324 * @hide 325 */ setSupport5gBand(boolean support5gBand)326 public Builder setSupport5gBand(boolean support5gBand) { 327 mSupport5gBand = support5gBand; 328 return this; 329 } 330 331 /** 332 * Specify whether 6G band support is required in this request. Disabled by default. 333 * 334 * @param support6gBand Support for 6G band is required. 335 * 336 * @return The builder to facilitate chaining 337 * {@code builder.setXXX(..).setXXX(..)}. 338 * @hide 339 */ setSupport6gBand(boolean support6gBand)340 public Builder setSupport6gBand(boolean support6gBand) { 341 mSupport6gBand = support6gBand; 342 return this; 343 } 344 345 /** 346 * Specify the Master Preference requested. The permitted range is 0 (the default) to 347 * 255 with 1 and 255 excluded (reserved). 348 * 349 * @param masterPreference The requested master preference 350 * 351 * @return The builder to facilitate chaining 352 * {@code builder.setXXX(..).setXXX(..)}. 353 * @hide 354 */ setMasterPreference(int masterPreference)355 public Builder setMasterPreference(int masterPreference) { 356 if (masterPreference < 0) { 357 throw new IllegalArgumentException( 358 "Master Preference specification must be non-negative"); 359 } 360 if (masterPreference == 1 || masterPreference == 255 || masterPreference > 255) { 361 throw new IllegalArgumentException("Master Preference specification must not " 362 + "exceed 255 or use 1 or 255 (reserved values)"); 363 } 364 365 mMasterPreference = masterPreference; 366 return this; 367 } 368 369 /** 370 * The Cluster ID is generated randomly for new Aware networks. Specify 371 * the lower range of the cluster ID. The upper range is specified using 372 * the {@link ConfigRequest.Builder#setClusterHigh(int)}. The permitted 373 * range is 0 (the default) to the value specified by 374 * {@link ConfigRequest.Builder#setClusterHigh(int)}. Equality of Low and High is 375 * permitted which restricts the Cluster ID to the specified value. 376 * 377 * @param clusterLow The lower range of the generated cluster ID. 378 * 379 * @return The builder to facilitate chaining 380 * {@code builder.setClusterLow(..).setClusterHigh(..)}. 381 * @hide 382 */ setClusterLow(int clusterLow)383 public Builder setClusterLow(int clusterLow) { 384 if (clusterLow < CLUSTER_ID_MIN) { 385 throw new IllegalArgumentException("Cluster specification must be non-negative"); 386 } 387 if (clusterLow > CLUSTER_ID_MAX) { 388 throw new IllegalArgumentException("Cluster specification must not exceed 0xFFFF"); 389 } 390 391 mClusterLow = clusterLow; 392 return this; 393 } 394 395 /** 396 * The Cluster ID is generated randomly for new Aware networks. Specify 397 * the lower upper of the cluster ID. The lower range is specified using 398 * the {@link ConfigRequest.Builder#setClusterLow(int)}. The permitted 399 * range is the value specified by 400 * {@link ConfigRequest.Builder#setClusterLow(int)} to 0xFFFF (the default). Equality of 401 * Low and High is permitted which restricts the Cluster ID to the specified value. 402 * 403 * @param clusterHigh The upper range of the generated cluster ID. 404 * 405 * @return The builder to facilitate chaining 406 * {@code builder.setClusterLow(..).setClusterHigh(..)}. 407 * @hide 408 */ setClusterHigh(int clusterHigh)409 public Builder setClusterHigh(int clusterHigh) { 410 if (clusterHigh < CLUSTER_ID_MIN) { 411 throw new IllegalArgumentException("Cluster specification must be non-negative"); 412 } 413 if (clusterHigh > CLUSTER_ID_MAX) { 414 throw new IllegalArgumentException("Cluster specification must not exceed 0xFFFF"); 415 } 416 417 mClusterHigh = clusterHigh; 418 return this; 419 } 420 421 /** 422 * The discovery window interval specifies the discovery windows in which the device will be 423 * awake. The configuration enables trading off latency vs. power (higher interval means 424 * higher discovery latency but lower power). 425 * 426 * @param band Either {@link #NAN_BAND_24GHZ} or {@link #NAN_BAND_5GHZ} or 427 * {@link #NAN_BAND_6GHZ}. 428 * @param interval A value of 1, 2, 3, 4, or 5 indicating an interval of 2^(interval-1). For 429 * the 5GHz band a value of 0 indicates that the device will not be awake 430 * for any discovery windows. 431 * 432 * @return The builder itself to facilitate chaining operations 433 * {@code builder.setDiscoveryWindowInterval(...).setMasterPreference(...)}. 434 * @hide 435 */ setDiscoveryWindowInterval(int band, int interval)436 public Builder setDiscoveryWindowInterval(int band, int interval) { 437 if (band != NAN_BAND_24GHZ && band != NAN_BAND_5GHZ && band != NAN_BAND_6GHZ) { 438 throw new IllegalArgumentException("Invalid band value"); 439 } 440 if ((band == NAN_BAND_24GHZ && (interval < 1 || interval > 5)) 441 || (band == NAN_BAND_5GHZ && (interval < 0 || interval > 5)) 442 || (band == NAN_BAND_6GHZ && (interval < 0 || interval > 5))) { 443 throw new IllegalArgumentException( 444 "Invalid interval value: 2.4 GHz [1,5] or 5GHz/6GHz [0,5]"); 445 } 446 447 mDiscoveryWindowInterval[band] = interval; 448 return this; 449 } 450 451 /** 452 * Set additional vendor-provided configuration data. 453 * 454 * @param vendorData List of {@link android.net.wifi.OuiKeyedData} containing the 455 * vendor-provided configuration data. Note that multiple elements with 456 * the same OUI are allowed. 457 * @return Builder for chaining. 458 * @hide 459 */ 460 @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) 461 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) 462 @SystemApi 463 @NonNull setVendorData(@onNull List<OuiKeyedData> vendorData)464 public Builder setVendorData(@NonNull List<OuiKeyedData> vendorData) { 465 if (!SdkLevel.isAtLeastV()) { 466 throw new UnsupportedOperationException(); 467 } 468 if (vendorData == null) { 469 throw new IllegalArgumentException("setVendorData received a null value"); 470 } 471 mVendorData = vendorData; 472 return this; 473 } 474 475 /** 476 * Build {@link ConfigRequest} given the current requests made on the 477 * builder. 478 */ 479 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) 480 @NonNull build()481 public ConfigRequest build() { 482 if (mClusterLow > mClusterHigh) { 483 throw new IllegalArgumentException( 484 "Invalid argument combination - must have Cluster Low <= Cluster High"); 485 } 486 487 return new ConfigRequest(mSupport5gBand, mSupport6gBand, mMasterPreference, mClusterLow, 488 mClusterHigh, mDiscoveryWindowInterval, mVendorData); 489 } 490 } 491 } 492