| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.net.wifi.aware; |
| |
| import static android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION; |
| |
| import android.annotation.IntDef; |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.annotation.RequiresPermission; |
| import android.annotation.SystemApi; |
| import android.net.wifi.WifiScanner; |
| import android.net.wifi.util.HexEncoding; |
| import android.os.Build; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| |
| import androidx.annotation.RequiresApi; |
| |
| import com.android.modules.utils.build.SdkLevel; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.nio.charset.StandardCharsets; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.Objects; |
| |
| /** |
| * Defines the configuration of an Aware subscribe session. Built using |
| * {@link SubscribeConfig.Builder}. Subscribe is done using |
| * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback, |
| * android.os.Handler)} or |
| * {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. |
| */ |
| public final class SubscribeConfig implements Parcelable { |
| /** @hide */ |
| @IntDef({ |
| SUBSCRIBE_TYPE_PASSIVE, SUBSCRIBE_TYPE_ACTIVE }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface SubscribeTypes { |
| } |
| |
| /** |
| * Defines a passive subscribe session - a subscribe session where |
| * subscribe packets are not transmitted over-the-air and the device listens |
| * and matches to transmitted publish packets. Configuration is done using |
| * {@link SubscribeConfig.Builder#setSubscribeType(int)}. |
| */ |
| public static final int SUBSCRIBE_TYPE_PASSIVE = 0; |
| |
| /** |
| * Defines an active subscribe session - a subscribe session where |
| * subscribe packets are transmitted over-the-air. Configuration is done |
| * using {@link SubscribeConfig.Builder#setSubscribeType(int)}. |
| */ |
| public static final int SUBSCRIBE_TYPE_ACTIVE = 1; |
| |
| /** @hide */ |
| public final byte[] mServiceName; |
| |
| /** @hide */ |
| public final byte[] mServiceSpecificInfo; |
| |
| /** @hide */ |
| public final byte[] mMatchFilter; |
| |
| /** @hide */ |
| public final int mSubscribeType; |
| |
| /** @hide */ |
| public final int mTtlSec; |
| |
| /** @hide */ |
| public final boolean mEnableTerminateNotification; |
| |
| /** @hide */ |
| public final boolean mMinDistanceMmSet; |
| |
| /** @hide */ |
| public final int mMinDistanceMm; |
| |
| /** @hide */ |
| public final boolean mMaxDistanceMmSet; |
| |
| /** @hide */ |
| public final int mMaxDistanceMm; |
| |
| private final boolean mEnableInstantMode; |
| |
| private final int mBand; |
| |
| private final AwarePairingConfig mPairingConfig; |
| |
| private final boolean mIsSuspendable; |
| |
| /** @hide */ |
| public SubscribeConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter, |
| int subscribeType, int ttlSec, boolean enableTerminateNotification, |
| boolean minDistanceMmSet, int minDistanceMm, boolean maxDistanceMmSet, |
| int maxDistanceMm, boolean enableInstantMode, @WifiScanner.WifiBand int band, |
| AwarePairingConfig pairingConfig, boolean isSuspendable) { |
| mServiceName = serviceName; |
| mServiceSpecificInfo = serviceSpecificInfo; |
| mMatchFilter = matchFilter; |
| mSubscribeType = subscribeType; |
| mTtlSec = ttlSec; |
| mEnableTerminateNotification = enableTerminateNotification; |
| mMinDistanceMm = minDistanceMm; |
| mMinDistanceMmSet = minDistanceMmSet; |
| mMaxDistanceMm = maxDistanceMm; |
| mMaxDistanceMmSet = maxDistanceMmSet; |
| mEnableInstantMode = enableInstantMode; |
| mBand = band; |
| mPairingConfig = pairingConfig; |
| mIsSuspendable = isSuspendable; |
| } |
| |
| @Override |
| public String toString() { |
| return "SubscribeConfig [mServiceName='" + (mServiceName == null ? "<null>" |
| : String.valueOf(HexEncoding.encode(mServiceName))) + ", mServiceName.length=" + ( |
| mServiceName == null ? 0 : mServiceName.length) + ", mServiceSpecificInfo='" + ( |
| (mServiceSpecificInfo == null) ? "<null>" : String.valueOf( |
| HexEncoding.encode(mServiceSpecificInfo))) |
| + ", mServiceSpecificInfo.length=" + (mServiceSpecificInfo == null ? 0 |
| : mServiceSpecificInfo.length) + ", mMatchFilter=" |
| + (new TlvBufferUtils.TlvIterable(0, 1, mMatchFilter)).toString() |
| + ", mMatchFilter.length=" + (mMatchFilter == null ? 0 : mMatchFilter.length) |
| + ", mSubscribeType=" + mSubscribeType + ", mTtlSec=" + mTtlSec |
| + ", mEnableTerminateNotification=" + mEnableTerminateNotification |
| + ", mMinDistanceMm=" + mMinDistanceMm |
| + ", mMinDistanceMmSet=" + mMinDistanceMmSet |
| + ", mMaxDistanceMm=" + mMaxDistanceMm |
| + ", mMaxDistanceMmSet=" + mMaxDistanceMmSet + "]" |
| + ", mEnableInstantMode=" + mEnableInstantMode |
| + ", mBand=" + mBand |
| + ", mPairingConfig" + mPairingConfig |
| + ", mIsSuspendable=" + mIsSuspendable; |
| } |
| |
| @Override |
| public int describeContents() { |
| return 0; |
| } |
| |
| @Override |
| public void writeToParcel(Parcel dest, int flags) { |
| dest.writeByteArray(mServiceName); |
| dest.writeByteArray(mServiceSpecificInfo); |
| dest.writeByteArray(mMatchFilter); |
| dest.writeInt(mSubscribeType); |
| dest.writeInt(mTtlSec); |
| dest.writeInt(mEnableTerminateNotification ? 1 : 0); |
| dest.writeInt(mMinDistanceMm); |
| dest.writeInt(mMinDistanceMmSet ? 1 : 0); |
| dest.writeInt(mMaxDistanceMm); |
| dest.writeInt(mMaxDistanceMmSet ? 1 : 0); |
| dest.writeBoolean(mEnableInstantMode); |
| dest.writeInt(mBand); |
| dest.writeParcelable(mPairingConfig, flags); |
| dest.writeBoolean(mIsSuspendable); |
| } |
| |
| @NonNull |
| public static final Creator<SubscribeConfig> CREATOR = new Creator<>() { |
| @Override |
| public SubscribeConfig[] newArray(int size) { |
| return new SubscribeConfig[size]; |
| } |
| |
| @Override |
| public SubscribeConfig createFromParcel(Parcel in) { |
| byte[] serviceName = in.createByteArray(); |
| byte[] ssi = in.createByteArray(); |
| byte[] matchFilter = in.createByteArray(); |
| int subscribeType = in.readInt(); |
| int ttlSec = in.readInt(); |
| boolean enableTerminateNotification = in.readInt() != 0; |
| int minDistanceMm = in.readInt(); |
| boolean minDistanceMmSet = in.readInt() != 0; |
| int maxDistanceMm = in.readInt(); |
| boolean maxDistanceMmSet = in.readInt() != 0; |
| boolean enableInstantMode = in.readBoolean(); |
| int band = in.readInt(); |
| AwarePairingConfig pairingConfig = in.readParcelable( |
| AwarePairingConfig.class.getClassLoader()); |
| boolean isSuspendable = in.readBoolean(); |
| |
| return new SubscribeConfig(serviceName, ssi, matchFilter, subscribeType, ttlSec, |
| enableTerminateNotification, minDistanceMmSet, minDistanceMm, maxDistanceMmSet, |
| maxDistanceMm, enableInstantMode, band, pairingConfig, isSuspendable); |
| } |
| }; |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) { |
| return true; |
| } |
| |
| if (!(o instanceof SubscribeConfig)) { |
| return false; |
| } |
| |
| SubscribeConfig lhs = (SubscribeConfig) o; |
| |
| if (!(Arrays.equals(mServiceName, lhs.mServiceName) && Arrays.equals( |
| mServiceSpecificInfo, lhs.mServiceSpecificInfo) && Arrays.equals(mMatchFilter, |
| lhs.mMatchFilter) && mSubscribeType == lhs.mSubscribeType && mTtlSec == lhs.mTtlSec |
| && mEnableTerminateNotification == lhs.mEnableTerminateNotification |
| && mMinDistanceMmSet == lhs.mMinDistanceMmSet |
| && mMaxDistanceMmSet == lhs.mMaxDistanceMmSet |
| && mEnableInstantMode == lhs.mEnableInstantMode |
| && mBand == lhs.mBand |
| && mIsSuspendable == lhs.mIsSuspendable)) { |
| return false; |
| } |
| |
| if (mMinDistanceMmSet && mMinDistanceMm != lhs.mMinDistanceMm) { |
| return false; |
| } |
| |
| if (mMaxDistanceMmSet && mMaxDistanceMm != lhs.mMaxDistanceMm) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public int hashCode() { |
| int result = Objects.hash(Arrays.hashCode(mServiceName), |
| Arrays.hashCode(mServiceSpecificInfo), Arrays.hashCode(mMatchFilter), |
| mSubscribeType, mTtlSec, mEnableTerminateNotification, mMinDistanceMmSet, |
| mMaxDistanceMmSet, mEnableInstantMode, mBand, mIsSuspendable); |
| |
| if (mMinDistanceMmSet) { |
| result = Objects.hash(result, mMinDistanceMm); |
| } |
| if (mMaxDistanceMmSet) { |
| result = Objects.hash(result, mMaxDistanceMm); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Verifies that the contents of the SubscribeConfig are valid. Otherwise |
| * throws an IllegalArgumentException. |
| * |
| * @hide |
| */ |
| public void assertValid(Characteristics characteristics, boolean rttSupported) |
| throws IllegalArgumentException { |
| WifiAwareUtils.validateServiceName(mServiceName); |
| |
| if (!TlvBufferUtils.isValid(mMatchFilter, 0, 1)) { |
| throw new IllegalArgumentException( |
| "Invalid matchFilter configuration - LV fields do not match up to length"); |
| } |
| if (mSubscribeType < SUBSCRIBE_TYPE_PASSIVE || mSubscribeType > SUBSCRIBE_TYPE_ACTIVE) { |
| throw new IllegalArgumentException("Invalid subscribeType - " + mSubscribeType); |
| } |
| if (mTtlSec < 0) { |
| throw new IllegalArgumentException("Invalid ttlSec - must be non-negative"); |
| } |
| |
| if (characteristics != null) { |
| int maxServiceNameLength = characteristics.getMaxServiceNameLength(); |
| if (maxServiceNameLength != 0 && mServiceName.length > maxServiceNameLength) { |
| throw new IllegalArgumentException( |
| "Service name longer than supported by device characteristics"); |
| } |
| int maxServiceSpecificInfoLength = characteristics.getMaxServiceSpecificInfoLength(); |
| if (maxServiceSpecificInfoLength != 0 && mServiceSpecificInfo != null |
| && mServiceSpecificInfo.length > maxServiceSpecificInfoLength) { |
| throw new IllegalArgumentException( |
| "Service specific info longer than supported by device characteristics"); |
| } |
| int maxMatchFilterLength = characteristics.getMaxMatchFilterLength(); |
| if (maxMatchFilterLength != 0 && mMatchFilter != null |
| && mMatchFilter.length > maxMatchFilterLength) { |
| throw new IllegalArgumentException( |
| "Match filter longer than supported by device characteristics"); |
| } |
| if (mEnableInstantMode) { |
| if (SdkLevel.isAtLeastT() |
| && characteristics.isInstantCommunicationModeSupported()) { |
| // Valid to use instant communication mode |
| } else { |
| throw new IllegalArgumentException("instant mode is not supported"); |
| } |
| } |
| if (mIsSuspendable && !characteristics.isSuspensionSupported()) { |
| throw new IllegalArgumentException("Aware Suspension is not supported"); |
| } |
| if (mPairingConfig != null && !characteristics.isAwarePairingSupported()) { |
| throw new IllegalArgumentException("Aware Pairing is not supported"); |
| } |
| } |
| |
| if (mMinDistanceMmSet && mMinDistanceMm < 0) { |
| throw new IllegalArgumentException("Minimum distance must be non-negative"); |
| } |
| if (mMaxDistanceMmSet && mMaxDistanceMm < 0) { |
| throw new IllegalArgumentException("Maximum distance must be non-negative"); |
| } |
| if (mMinDistanceMmSet && mMaxDistanceMmSet && mMaxDistanceMm <= mMinDistanceMm) { |
| throw new IllegalArgumentException( |
| "Maximum distance must be greater than minimum distance"); |
| } |
| |
| if (!rttSupported && (mMinDistanceMmSet || mMaxDistanceMmSet)) { |
| throw new IllegalArgumentException("Ranging is not supported"); |
| } |
| } |
| |
| /** |
| * Check if instant mode is enabled for this subscribe session. |
| * @see Builder#setInstantCommunicationModeEnabled(boolean, int) |
| * @return true for enabled, false otherwise. |
| */ |
| public boolean isInstantCommunicationModeEnabled() { |
| return mEnableInstantMode; |
| } |
| |
| /** |
| * Check if enable instant mode on 5G for this subscribe session |
| * @see Builder#setInstantCommunicationModeEnabled(boolean, int) |
| * @return The Wi-Fi band, one of the {@link WifiScanner#WIFI_BAND_24_GHZ} |
| * or {@link WifiScanner#WIFI_BAND_5_GHZ}. If instant communication mode is not enabled will |
| * return {@link WifiScanner#WIFI_BAND_24_GHZ} as default. |
| */ |
| @WifiScanner.WifiBand |
| public int getInstantCommunicationBand() { |
| return mBand; |
| } |
| |
| /** |
| * Get the Aware Pairing config for this subscribe session |
| * @see Builder#setPairingConfig(AwarePairingConfig) |
| * @return A {@link AwarePairingConfig} specified in this config. |
| */ |
| @Nullable |
| public AwarePairingConfig getPairingConfig() { |
| return mPairingConfig; |
| } |
| |
| /** |
| * Check if suspension is supported for this subscribe session. |
| * @see Builder#setSuspendable(boolean) |
| * @return true for supported, false otherwise. |
| * @hide |
| */ |
| @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) |
| @SystemApi |
| public boolean isSuspendable() { |
| if (!SdkLevel.isAtLeastU()) { |
| throw new UnsupportedOperationException(); |
| } |
| return mIsSuspendable; |
| } |
| |
| /** |
| * Builder used to build {@link SubscribeConfig} objects. |
| */ |
| public static final class Builder { |
| private byte[] mServiceName; |
| private byte[] mServiceSpecificInfo; |
| private byte[] mMatchFilter; |
| private int mSubscribeType = SUBSCRIBE_TYPE_PASSIVE; |
| private int mTtlSec = 0; |
| private boolean mEnableTerminateNotification = true; |
| private boolean mMinDistanceMmSet = false; |
| private int mMinDistanceMm; |
| private boolean mMaxDistanceMmSet = false; |
| private int mMaxDistanceMm; |
| private boolean mEnableInstantMode; |
| private int mBand = WifiScanner.WIFI_BAND_24_GHZ; |
| private AwarePairingConfig mPairingConfig; |
| private boolean mIsSuspendable = false; |
| |
| /** |
| * Specify the service name of the subscribe session. The actual on-air |
| * value is a 6 byte hashed representation of this string. |
| * <p> |
| * The Service Name is a UTF-8 encoded string from 1 to 255 bytes in length. |
| * The only acceptable single-byte UTF-8 symbols for a Service Name are alphanumeric |
| * values (A-Z, a-z, 0-9), the hyphen ('-'), the period ('.') and the underscore ('_'). All |
| * valid multi-byte UTF-8 characters are acceptable in a Service Name. |
| * <p> |
| * Must be called - an empty ServiceName is not valid. |
| * |
| * @param serviceName The service name for the subscribe session. |
| * |
| * @return The builder to facilitate chaining |
| * {@code builder.setXXX(..).setXXX(..)}. |
| */ |
| public Builder setServiceName(@NonNull String serviceName) { |
| if (serviceName == null) { |
| throw new IllegalArgumentException("Invalid service name - must be non-null"); |
| } |
| mServiceName = serviceName.getBytes(StandardCharsets.UTF_8); |
| return this; |
| } |
| |
| /** |
| * Specify service specific information for the subscribe session. This is |
| * a free-form byte array available to the application to send |
| * additional information as part of the discovery operation - i.e. it |
| * will not be used to determine whether a publish/subscribe match |
| * occurs. |
| * <p> |
| * Optional. Empty by default. |
| * |
| * @param serviceSpecificInfo A byte-array for the service-specific |
| * information field. |
| * |
| * @return The builder to facilitate chaining |
| * {@code builder.setXXX(..).setXXX(..)}. |
| */ |
| public Builder setServiceSpecificInfo(@Nullable byte[] serviceSpecificInfo) { |
| mServiceSpecificInfo = serviceSpecificInfo; |
| return this; |
| } |
| |
| /** |
| * The match filter for a subscribe session. Used to determine whether a service |
| * discovery occurred - in addition to relying on the service name. |
| * <p> |
| * Optional. Empty by default. |
| * |
| * @param matchFilter A list of match filter entries (each of which is an arbitrary byte |
| * array). |
| * |
| * @return The builder to facilitate chaining |
| * {@code builder.setXXX(..).setXXX(..)}. |
| */ |
| public Builder setMatchFilter(@Nullable List<byte[]> matchFilter) { |
| mMatchFilter = new TlvBufferUtils.TlvConstructor(0, 1).allocateAndPut( |
| matchFilter).getArray(); |
| return this; |
| } |
| |
| /** |
| * Sets the type of the subscribe session: active (subscribe packets are |
| * transmitted over-the-air), or passive (no subscribe packets are |
| * transmitted, a match is made against a solicited/active publish |
| * session whose packets are transmitted over-the-air). |
| * |
| * @param subscribeType Subscribe session type: |
| * {@link SubscribeConfig#SUBSCRIBE_TYPE_ACTIVE} or |
| * {@link SubscribeConfig#SUBSCRIBE_TYPE_PASSIVE}. |
| * |
| * @return The builder to facilitate chaining |
| * {@code builder.setXXX(..).setXXX(..)}. |
| */ |
| public Builder setSubscribeType(@SubscribeTypes int subscribeType) { |
| if (subscribeType < SUBSCRIBE_TYPE_PASSIVE || subscribeType > SUBSCRIBE_TYPE_ACTIVE) { |
| throw new IllegalArgumentException("Invalid subscribeType - " + subscribeType); |
| } |
| mSubscribeType = subscribeType; |
| return this; |
| } |
| |
| /** |
| * Sets the time interval (in seconds) an active ( |
| * {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe session |
| * will be alive - i.e. broadcasting a packet. When the TTL is reached |
| * an event will be generated for |
| * {@link DiscoverySessionCallback#onSessionTerminated()}. |
| * <p> |
| * Optional. 0 by default - indicating the session doesn't terminate on its own. |
| * Session will be terminated when {@link DiscoverySession#close()} is |
| * called. |
| * |
| * @param ttlSec Lifetime of a subscribe session in seconds. |
| * |
| * @return The builder to facilitate chaining |
| * {@code builder.setXXX(..).setXXX(..)}. |
| */ |
| public Builder setTtlSec(int ttlSec) { |
| if (ttlSec < 0) { |
| throw new IllegalArgumentException("Invalid ttlSec - must be non-negative"); |
| } |
| mTtlSec = ttlSec; |
| return this; |
| } |
| |
| /** |
| * Configure whether a subscribe terminate notification |
| * {@link DiscoverySessionCallback#onSessionTerminated()} is reported |
| * back to the callback. |
| * |
| * @param enable If true the terminate callback will be called when the |
| * subscribe is terminated. Otherwise it will not be called. |
| * |
| * @return The builder to facilitate chaining |
| * {@code builder.setXXX(..).setXXX(..)}. |
| */ |
| public Builder setTerminateNotificationEnabled(boolean enable) { |
| mEnableTerminateNotification = enable; |
| return this; |
| } |
| |
| /** |
| * Configure the minimum distance to a discovered publisher at which to trigger a discovery |
| * notification. I.e. discovery will be triggered if we've found a matching publisher |
| * (based on the other criteria in this configuration) <b>and</b> the distance to the |
| * publisher is larger than the value specified in this API. Can be used in conjunction with |
| * {@link #setMaxDistanceMm(int)} to specify a geofence, i.e. discovery with min <= |
| * distance <= max. |
| * <p> |
| * For ranging to be used in discovery it must also be enabled on the publisher using |
| * {@link PublishConfig.Builder#setRangingEnabled(boolean)}. However, ranging may |
| * not be available or enabled on the publisher or may be temporarily disabled on either |
| * subscriber or publisher - in such cases discovery will proceed without ranging. |
| * <p> |
| * When ranging is enabled and available on both publisher and subscriber and a service |
| * is discovered based on geofence constraints the |
| * {@link DiscoverySessionCallback#onServiceDiscoveredWithinRange(PeerHandle, byte[], List, int)} |
| * is called, otherwise the |
| * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], List)} |
| * is called. |
| * <p> |
| * The device must support Wi-Fi RTT for this feature to be used. Feature support is checked |
| * as described in {@link android.net.wifi.rtt}. |
| * |
| * @param minDistanceMm Minimum distance, in mm, to the publisher above which to trigger |
| * discovery. |
| * |
| * @return The builder to facilitate chaining |
| * {@code builder.setXXX(..).setXXX(..)}. |
| */ |
| public Builder setMinDistanceMm(int minDistanceMm) { |
| mMinDistanceMm = minDistanceMm; |
| mMinDistanceMmSet = true; |
| return this; |
| } |
| |
| /** |
| * Configure the maximum distance to a discovered publisher at which to trigger a discovery |
| * notification. I.e. discovery will be triggered if we've found a matching publisher |
| * (based on the other criteria in this configuration) <b>and</b> the distance to the |
| * publisher is smaller than the value specified in this API. Can be used in conjunction |
| * with {@link #setMinDistanceMm(int)} to specify a geofence, i.e. discovery with min <= |
| * distance <= max. |
| * <p> |
| * For ranging to be used in discovery it must also be enabled on the publisher using |
| * {@link PublishConfig.Builder#setRangingEnabled(boolean)}. However, ranging may |
| * not be available or enabled on the publisher or may be temporarily disabled on either |
| * subscriber or publisher - in such cases discovery will proceed without ranging. |
| * <p> |
| * When ranging is enabled and available on both publisher and subscriber and a service |
| * is discovered based on geofence constraints the |
| * {@link DiscoverySessionCallback#onServiceDiscoveredWithinRange(PeerHandle, byte[], List, int)} |
| * is called, otherwise the |
| * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], List)} |
| * is called. |
| * <p> |
| * The device must support Wi-Fi RTT for this feature to be used. Feature support is checked |
| * as described in {@link android.net.wifi.rtt}. |
| * |
| * @param maxDistanceMm Maximum distance, in mm, to the publisher below which to trigger |
| * discovery. |
| * |
| * @return The builder to facilitate chaining |
| * {@code builder.setXXX(..).setXXX(..)}. |
| */ |
| public Builder setMaxDistanceMm(int maxDistanceMm) { |
| mMaxDistanceMm = maxDistanceMm; |
| mMaxDistanceMmSet = true; |
| return this; |
| } |
| |
| /** |
| * Configure whether to enable and use instant communication for this subscribe session. |
| * Instant communication will speed up service discovery and any data-path set up as part of |
| * this session. Use {@link Characteristics#isInstantCommunicationModeSupported()} to check |
| * if the device supports this feature. |
| * |
| * Note: due to increased power requirements of this mode - it will only remain enabled for |
| * 30 seconds from the time the discovery session is started. |
| * |
| * @param enabled true for enable instant communication mode, default is false. |
| * @param band Either {@link WifiScanner#WIFI_BAND_24_GHZ} |
| * or {@link WifiScanner#WIFI_BAND_5_GHZ}. When setting to |
| * {@link WifiScanner#WIFI_BAND_5_GHZ}, device will try to enable instant |
| * communication mode on 5Ghz, but may fall back to 2.4Ghz due to regulatory |
| * requirements. |
| * @return the current {@link Builder} builder, enabling chaining of builder methods. |
| */ |
| @RequiresApi(Build.VERSION_CODES.TIRAMISU) |
| @NonNull |
| public Builder setInstantCommunicationModeEnabled(boolean enabled, |
| @WifiScanner.WifiBand int band) { |
| if (!SdkLevel.isAtLeastT()) { |
| throw new UnsupportedOperationException(); |
| } |
| if (band != WifiScanner.WIFI_BAND_24_GHZ && band != WifiScanner.WIFI_BAND_5_GHZ) { |
| throw new IllegalArgumentException(); |
| } |
| mBand = band; |
| mEnableInstantMode = enabled; |
| return this; |
| } |
| |
| /** |
| * Set the {@link AwarePairingConfig} for this subscribe session, the peer can use this info |
| * to determine the config of the following bootstrapping, pairing setup/verification |
| * request. |
| * @see AwarePairingConfig |
| * @param config The pairing config set to the peer. Only valid when |
| * {@link Characteristics#isAwarePairingSupported()} is true. |
| * @return the current {@link Builder} builder, enabling chaining of builder methods. |
| */ |
| @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) |
| @NonNull public Builder setPairingConfig(@Nullable AwarePairingConfig config) { |
| if (!SdkLevel.isAtLeastU()) { |
| throw new UnsupportedOperationException(); |
| } |
| mPairingConfig = config; |
| return this; |
| } |
| |
| /** |
| * Specify whether to configure the subscribe discovery session to be suspendable. This API |
| * doesn't suspend the session, it allows it to be suspended and resumed in the future using |
| * {@link DiscoverySession#suspend()} and {@link DiscoverySession#resume()} respectively. |
| * <p> |
| * Optional. Not suspendable by default. |
| * <p> |
| * The device must support Wi-Fi Aware suspension for a subscribe session to be |
| * suspendable. Feature support check is determined by |
| * {@link Characteristics#isSuspensionSupported()}. |
| * |
| * @param isSuspendable If true, then this subscribe session can be suspended. |
| * |
| * @return the current {@link Builder} builder, enabling chaining of builder methods. |
| * |
| * @see DiscoverySession#suspend() |
| * @see DiscoverySession#resume() |
| * @hide |
| */ |
| @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) |
| @RequiresPermission(value = MANAGE_WIFI_NETWORK_SELECTION) |
| @SystemApi |
| @NonNull |
| public Builder setSuspendable(boolean isSuspendable) { |
| if (!SdkLevel.isAtLeastU()) { |
| throw new UnsupportedOperationException(); |
| } |
| mIsSuspendable = isSuspendable; |
| return this; |
| } |
| |
| /** |
| * Build {@link SubscribeConfig} given the current requests made on the |
| * builder. |
| */ |
| public SubscribeConfig build() { |
| return new SubscribeConfig(mServiceName, mServiceSpecificInfo, mMatchFilter, |
| mSubscribeType, mTtlSec, mEnableTerminateNotification, |
| mMinDistanceMmSet, mMinDistanceMm, mMaxDistanceMmSet, mMaxDistanceMm, |
| mEnableInstantMode, mBand, mPairingConfig, mIsSuspendable); |
| } |
| } |
| } |