| /* |
| * Copyright (C) 2017 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.bluetooth.le; |
| |
| import android.bluetooth.BluetoothAdapter; |
| import android.bluetooth.BluetoothDevice; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| |
| /** |
| * The {@link AdvertisingSetParameters} provide a way to adjust advertising |
| * preferences for each |
| * Bluetooth LE advertising set. Use {@link AdvertisingSetParameters.Builder} to |
| * create an |
| * instance of this class. |
| */ |
| public final class AdvertisingSetParameters implements Parcelable { |
| |
| /** |
| * Advertise on low frequency, around every 1000ms. This is the default and |
| * preferred advertising mode as it consumes the least power. |
| */ |
| public static final int INTERVAL_LOW = 1600; |
| |
| /** |
| * Advertise on medium frequency, around every 250ms. This is balanced |
| * between advertising frequency and power consumption. |
| */ |
| public static final int INTERVAL_MEDIUM = 400; |
| |
| /** |
| * Perform high frequency, low latency advertising, around every 100ms. This |
| * has the highest power consumption and should not be used for continuous |
| * background advertising. |
| */ |
| public static final int INTERVAL_HIGH = 160; |
| |
| /** |
| * Minimum value for advertising interval. |
| */ |
| public static final int INTERVAL_MIN = 160; |
| |
| /** |
| * Maximum value for advertising interval. |
| */ |
| public static final int INTERVAL_MAX = 16777215; |
| |
| /** |
| * Advertise using the lowest transmission (TX) power level. Low transmission |
| * power can be used to restrict the visibility range of advertising packets. |
| */ |
| public static final int TX_POWER_ULTRA_LOW = -21; |
| |
| /** |
| * Advertise using low TX power level. |
| */ |
| public static final int TX_POWER_LOW = -15; |
| |
| /** |
| * Advertise using medium TX power level. |
| */ |
| public static final int TX_POWER_MEDIUM = -7; |
| |
| /** |
| * Advertise using high TX power level. This corresponds to largest visibility |
| * range of the advertising packet. |
| */ |
| public static final int TX_POWER_HIGH = 1; |
| |
| /** |
| * Minimum value for TX power. |
| */ |
| public static final int TX_POWER_MIN = -127; |
| |
| /** |
| * Maximum value for TX power. |
| */ |
| public static final int TX_POWER_MAX = 1; |
| |
| /** |
| * The maximum limited advertisement duration as specified by the Bluetooth |
| * SIG |
| */ |
| private static final int LIMITED_ADVERTISING_MAX_MILLIS = 180 * 1000; |
| |
| private final boolean isLegacy; |
| private final boolean isAnonymous; |
| private final boolean includeTxPower; |
| private final int primaryPhy; |
| private final int secondaryPhy; |
| private final boolean connectable; |
| private final boolean scannable; |
| private final int interval; |
| private final int txPowerLevel; |
| |
| private AdvertisingSetParameters(boolean connectable, boolean scannable, boolean isLegacy, |
| boolean isAnonymous, boolean includeTxPower, |
| int primaryPhy, int secondaryPhy, |
| int interval, int txPowerLevel) { |
| this.connectable = connectable; |
| this.scannable = scannable; |
| this.isLegacy = isLegacy; |
| this.isAnonymous = isAnonymous; |
| this.includeTxPower = includeTxPower; |
| this.primaryPhy = primaryPhy; |
| this.secondaryPhy = secondaryPhy; |
| this.interval = interval; |
| this.txPowerLevel = txPowerLevel; |
| } |
| |
| private AdvertisingSetParameters(Parcel in) { |
| connectable = in.readInt() != 0 ? true : false; |
| scannable = in.readInt() != 0 ? true : false; |
| isLegacy = in.readInt() != 0 ? true : false; |
| isAnonymous = in.readInt() != 0 ? true : false; |
| includeTxPower = in.readInt() != 0 ? true : false; |
| primaryPhy = in.readInt(); |
| secondaryPhy = in.readInt(); |
| interval = in.readInt(); |
| txPowerLevel = in.readInt(); |
| } |
| |
| /** |
| * Returns whether the advertisement will be connectable. |
| */ |
| public boolean isConnectable() { return connectable; } |
| |
| /** |
| * Returns whether the advertisement will be scannable. |
| */ |
| public boolean isScannable() { return scannable; } |
| |
| /** |
| * Returns whether the legacy advertisement will be used. |
| */ |
| public boolean isLegacy() { return isLegacy; } |
| |
| /** |
| * Returns whether the advertisement will be anonymous. |
| */ |
| public boolean isAnonymous() { return isAnonymous; } |
| |
| /** |
| * Returns whether the TX Power will be included. |
| */ |
| public boolean includeTxPower() { return includeTxPower; } |
| |
| /** |
| * Returns the primary advertising phy. |
| */ |
| public int getPrimaryPhy() { return primaryPhy; } |
| |
| /** |
| * Returns the secondary advertising phy. |
| */ |
| public int getSecondaryPhy() { return secondaryPhy; } |
| |
| /** |
| * Returns the advertising interval. |
| */ |
| public int getInterval() { return interval; } |
| |
| /** |
| * Returns the TX power level for advertising. |
| */ |
| public int getTxPowerLevel() { return txPowerLevel; } |
| |
| @Override |
| public String toString() { |
| return "AdvertisingSetParameters [connectable=" + connectable |
| + ", isLegacy=" + isLegacy |
| + ", isAnonymous=" + isAnonymous |
| + ", includeTxPower=" + includeTxPower |
| + ", primaryPhy=" + primaryPhy |
| + ", secondaryPhy=" + secondaryPhy |
| + ", interval=" + interval |
| + ", txPowerLevel=" + txPowerLevel + "]"; |
| } |
| |
| @Override |
| public int describeContents() { |
| return 0; |
| } |
| |
| @Override |
| public void writeToParcel(Parcel dest, int flags) { |
| dest.writeInt(connectable ? 1 : 0); |
| dest.writeInt(scannable ? 1 : 0); |
| dest.writeInt(isLegacy ? 1 : 0); |
| dest.writeInt(isAnonymous ? 1 : 0); |
| dest.writeInt(includeTxPower ? 1 : 0); |
| dest.writeInt(primaryPhy); |
| dest.writeInt(secondaryPhy); |
| dest.writeInt(interval); |
| dest.writeInt(txPowerLevel); |
| } |
| |
| public static final Parcelable.Creator<AdvertisingSetParameters> CREATOR = |
| new Creator<AdvertisingSetParameters>() { |
| @Override |
| public AdvertisingSetParameters[] newArray(int size) { |
| return new AdvertisingSetParameters[size]; |
| } |
| |
| @Override |
| public AdvertisingSetParameters createFromParcel(Parcel in) { |
| return new AdvertisingSetParameters(in); |
| } |
| }; |
| |
| /** |
| * Builder class for {@link AdvertisingSetParameters}. |
| */ |
| public static final class Builder { |
| |
| private boolean connectable = false; |
| private boolean scannable = false; |
| private boolean isLegacy = false; |
| private boolean isAnonymous = false; |
| private boolean includeTxPower = false; |
| private int primaryPhy = BluetoothDevice.PHY_LE_1M; |
| private int secondaryPhy = BluetoothDevice.PHY_LE_1M; |
| private int interval = INTERVAL_LOW; |
| private int txPowerLevel = TX_POWER_MEDIUM; |
| |
| /** |
| * Set whether the advertisement type should be connectable or |
| * non-connectable. |
| * Legacy advertisements can be both connectable and scannable. Non-legacy |
| * advertisements can be only scannable or only connectable. |
| * @param connectable Controls whether the advertisement type will be |
| * connectable (true) or non-connectable (false). |
| */ |
| public Builder setConnectable(boolean connectable) { |
| this.connectable = connectable; |
| return this; |
| } |
| |
| /** |
| * Set whether the advertisement type should be scannable. |
| * Legacy advertisements can be both connectable and scannable. Non-legacy |
| * advertisements can be only scannable or only connectable. |
| * @param scannable Controls whether the advertisement type will be |
| * scannable (true) or non-scannable (false). |
| */ |
| public Builder setScannable(boolean scannable) { |
| this.scannable = scannable; |
| return this; |
| } |
| |
| /** |
| * When set to true, advertising set will advertise 4.x Spec compliant |
| * advertisements. |
| * |
| * @param isLegacy whether legacy advertising mode should be used. |
| */ |
| public Builder setLegacyMode(boolean isLegacy) { |
| this.isLegacy = isLegacy; |
| return this; |
| } |
| |
| /** |
| * Set whether advertiser address should be ommited from all packets. If this |
| * mode is used, periodic advertising can't be enabled for this set. |
| * |
| * This is used only if legacy mode is not used. |
| * |
| * @param isAnonymous whether anonymous advertising should be used. |
| */ |
| public Builder setAnonymous(boolean isAnonymous) { |
| this.isAnonymous = isAnonymous; |
| return this; |
| } |
| |
| /** |
| * Set whether TX power should be included in the extended header. |
| * |
| * This is used only if legacy mode is not used. |
| * |
| * @param includeTxPower whether TX power should be included in extended |
| * header |
| */ |
| public Builder setIncludeTxPower(boolean includeTxPower) { |
| this.includeTxPower = includeTxPower; |
| return this; |
| } |
| |
| /** |
| * Set the primary physical channel used for this advertising set. |
| * |
| * This is used only if legacy mode is not used. |
| * |
| * Use {@link BluetoothAdapter#isLeCodedPhySupported} to determine if LE Coded PHY is |
| * supported on this device. |
| * @param primaryPhy Primary advertising physical channel, can only be |
| * {@link BluetoothDevice#PHY_LE_1M} or |
| * {@link BluetoothDevice#PHY_LE_CODED}. |
| * @throws IllegalArgumentException If the primaryPhy is invalid. |
| */ |
| public Builder setPrimaryPhy(int primaryPhy) { |
| if (primaryPhy != BluetoothDevice.PHY_LE_1M && |
| primaryPhy != BluetoothDevice.PHY_LE_CODED) { |
| throw new IllegalArgumentException("bad primaryPhy " + primaryPhy); |
| } |
| this.primaryPhy = primaryPhy; |
| return this; |
| } |
| |
| /** |
| * Set the secondary physical channel used for this advertising set. |
| * |
| * This is used only if legacy mode is not used. |
| * |
| * Use {@link BluetoothAdapter#isLeCodedPhySupported} and |
| * {@link BluetoothAdapter#isLe2MPhySupported} to determine if LE Coded PHY or 2M PHY is |
| * supported on this device. |
| * |
| * @param secondaryPhy Secondary advertising physical channel, can only be |
| * one of {@link BluetoothDevice#PHY_LE_1M}, |
| * {@link BluetoothDevice#PHY_LE_2M} or |
| * {@link BluetoothDevice#PHY_LE_CODED}. |
| * @throws IllegalArgumentException If the secondaryPhy is invalid. |
| */ |
| public Builder setSecondaryPhy(int secondaryPhy) { |
| if (secondaryPhy != BluetoothDevice.PHY_LE_1M && |
| secondaryPhy != BluetoothDevice.PHY_LE_2M && |
| secondaryPhy != BluetoothDevice.PHY_LE_CODED) { |
| throw new IllegalArgumentException("bad secondaryPhy " + secondaryPhy); |
| } |
| this.secondaryPhy = secondaryPhy; |
| return this; |
| } |
| |
| /** |
| * Set advertising interval. |
| * |
| * @param interval Bluetooth LE Advertising interval, in 0.625ms unit. Valid |
| * range is from 160 (100ms) to 16777215 (10,485.759375 s). |
| * Recommended values are: |
| * {@link AdvertisingSetParameters#INTERVAL_LOW}, |
| * {@link AdvertisingSetParameters#INTERVAL_MEDIUM}, or |
| * {@link AdvertisingSetParameters#INTERVAL_HIGH}. |
| * @throws IllegalArgumentException If the interval is invalid. |
| */ |
| public Builder setInterval(int interval) { |
| if (interval < INTERVAL_MIN || interval > INTERVAL_MAX) { |
| throw new IllegalArgumentException("unknown interval " + interval); |
| } |
| this.interval = interval; |
| return this; |
| } |
| |
| /** |
| * Set the transmission power level for the advertising. |
| * @param txPowerLevel Transmission power of Bluetooth LE Advertising, in |
| * dBm. The valid range is [-127, 1] Recommended values are: |
| * {@link AdvertisingSetParameters#TX_POWER_ULTRA_LOW}, |
| * {@link AdvertisingSetParameters#TX_POWER_LOW}, |
| * {@link AdvertisingSetParameters#TX_POWER_MEDIUM}, or |
| * {@link AdvertisingSetParameters#TX_POWER_HIGH}. |
| * |
| * @throws IllegalArgumentException If the {@code txPowerLevel} is invalid. |
| */ |
| public Builder setTxPowerLevel(int txPowerLevel) { |
| if (txPowerLevel < TX_POWER_MIN || txPowerLevel > TX_POWER_MAX) { |
| throw new IllegalArgumentException("unknown txPowerLevel " + |
| txPowerLevel); |
| } |
| this.txPowerLevel = txPowerLevel; |
| return this; |
| } |
| |
| /** |
| * Build the {@link AdvertisingSetParameters} object. |
| * @throws IllegalStateException if invalid combination of parameters is used. |
| */ |
| public AdvertisingSetParameters build() { |
| if (isLegacy) { |
| if (isAnonymous) { |
| throw new IllegalArgumentException("Legacy advertising can't be anonymous"); |
| } |
| |
| if (connectable == true && scannable == false) { |
| throw new IllegalStateException( |
| "Legacy advertisement can't be connectable and non-scannable"); |
| } |
| |
| if (includeTxPower) { |
| throw new IllegalStateException( |
| "Legacy advertising can't include TX power level in header"); |
| } |
| } else { |
| if (connectable && scannable) { |
| throw new IllegalStateException( |
| "Advertising can't be both connectable and scannable"); |
| } |
| |
| if (isAnonymous && connectable) { |
| throw new IllegalStateException( |
| "Advertising can't be both connectable and anonymous"); |
| } |
| } |
| |
| return new AdvertisingSetParameters(connectable, scannable, isLegacy, isAnonymous, |
| includeTxPower, primaryPhy, |
| secondaryPhy, interval, txPowerLevel); |
| } |
| } |
| } |