| /* |
| * 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_HIGH = 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_LOW = 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 mIsLegacy; |
| private final boolean mIsAnonymous; |
| private final boolean mIncludeTxPower; |
| private final int mPrimaryPhy; |
| private final int mSecondaryPhy; |
| private final boolean mConnectable; |
| private final boolean mScannable; |
| private final int mInterval; |
| private final int mTxPowerLevel; |
| |
| private AdvertisingSetParameters(boolean connectable, boolean scannable, boolean isLegacy, |
| boolean isAnonymous, boolean includeTxPower, |
| int primaryPhy, int secondaryPhy, |
| int interval, int txPowerLevel) { |
| mConnectable = connectable; |
| mScannable = scannable; |
| mIsLegacy = isLegacy; |
| mIsAnonymous = isAnonymous; |
| mIncludeTxPower = includeTxPower; |
| mPrimaryPhy = primaryPhy; |
| mSecondaryPhy = secondaryPhy; |
| mInterval = interval; |
| mTxPowerLevel = txPowerLevel; |
| } |
| |
| private AdvertisingSetParameters(Parcel in) { |
| mConnectable = in.readInt() != 0; |
| mScannable = in.readInt() != 0; |
| mIsLegacy = in.readInt() != 0; |
| mIsAnonymous = in.readInt() != 0; |
| mIncludeTxPower = in.readInt() != 0; |
| mPrimaryPhy = in.readInt(); |
| mSecondaryPhy = in.readInt(); |
| mInterval = in.readInt(); |
| mTxPowerLevel = in.readInt(); |
| } |
| |
| /** |
| * Returns whether the advertisement will be connectable. |
| */ |
| public boolean isConnectable() { |
| return mConnectable; |
| } |
| |
| /** |
| * Returns whether the advertisement will be scannable. |
| */ |
| public boolean isScannable() { |
| return mScannable; |
| } |
| |
| /** |
| * Returns whether the legacy advertisement will be used. |
| */ |
| public boolean isLegacy() { |
| return mIsLegacy; |
| } |
| |
| /** |
| * Returns whether the advertisement will be anonymous. |
| */ |
| public boolean isAnonymous() { |
| return mIsAnonymous; |
| } |
| |
| /** |
| * Returns whether the TX Power will be included. |
| */ |
| public boolean includeTxPower() { |
| return mIncludeTxPower; |
| } |
| |
| /** |
| * Returns the primary advertising phy. |
| */ |
| public int getPrimaryPhy() { |
| return mPrimaryPhy; |
| } |
| |
| /** |
| * Returns the secondary advertising phy. |
| */ |
| public int getSecondaryPhy() { |
| return mSecondaryPhy; |
| } |
| |
| /** |
| * Returns the advertising interval. |
| */ |
| public int getInterval() { |
| return mInterval; |
| } |
| |
| /** |
| * Returns the TX power level for advertising. |
| */ |
| public int getTxPowerLevel() { |
| return mTxPowerLevel; |
| } |
| |
| @Override |
| public String toString() { |
| return "AdvertisingSetParameters [connectable=" + mConnectable |
| + ", isLegacy=" + mIsLegacy |
| + ", isAnonymous=" + mIsAnonymous |
| + ", includeTxPower=" + mIncludeTxPower |
| + ", primaryPhy=" + mPrimaryPhy |
| + ", secondaryPhy=" + mSecondaryPhy |
| + ", interval=" + mInterval |
| + ", txPowerLevel=" + mTxPowerLevel + "]"; |
| } |
| |
| @Override |
| public int describeContents() { |
| return 0; |
| } |
| |
| @Override |
| public void writeToParcel(Parcel dest, int flags) { |
| dest.writeInt(mConnectable ? 1 : 0); |
| dest.writeInt(mScannable ? 1 : 0); |
| dest.writeInt(mIsLegacy ? 1 : 0); |
| dest.writeInt(mIsAnonymous ? 1 : 0); |
| dest.writeInt(mIncludeTxPower ? 1 : 0); |
| dest.writeInt(mPrimaryPhy); |
| dest.writeInt(mSecondaryPhy); |
| dest.writeInt(mInterval); |
| dest.writeInt(mTxPowerLevel); |
| } |
| |
| 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 mConnectable = false; |
| private boolean mScannable = false; |
| private boolean mIsLegacy = false; |
| private boolean mIsAnonymous = false; |
| private boolean mIncludeTxPower = false; |
| private int mPrimaryPhy = BluetoothDevice.PHY_LE_1M; |
| private int mSecondaryPhy = BluetoothDevice.PHY_LE_1M; |
| private int mInterval = INTERVAL_LOW; |
| private int mTxPowerLevel = 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) { |
| mConnectable = 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) { |
| mScannable = 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) { |
| mIsLegacy = 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) { |
| mIsAnonymous = 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) { |
| mIncludeTxPower = 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); |
| } |
| mPrimaryPhy = 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); |
| } |
| mSecondaryPhy = 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); |
| } |
| mInterval = 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); |
| } |
| mTxPowerLevel = txPowerLevel; |
| return this; |
| } |
| |
| /** |
| * Build the {@link AdvertisingSetParameters} object. |
| * |
| * @throws IllegalStateException if invalid combination of parameters is used. |
| */ |
| public AdvertisingSetParameters build() { |
| if (mIsLegacy) { |
| if (mIsAnonymous) { |
| throw new IllegalArgumentException("Legacy advertising can't be anonymous"); |
| } |
| |
| if (mConnectable && !mScannable) { |
| throw new IllegalStateException( |
| "Legacy advertisement can't be connectable and non-scannable"); |
| } |
| |
| if (mIncludeTxPower) { |
| throw new IllegalStateException( |
| "Legacy advertising can't include TX power level in header"); |
| } |
| } else { |
| if (mConnectable && mScannable) { |
| throw new IllegalStateException( |
| "Advertising can't be both connectable and scannable"); |
| } |
| |
| if (mIsAnonymous && mConnectable) { |
| throw new IllegalStateException( |
| "Advertising can't be both connectable and anonymous"); |
| } |
| } |
| |
| return new AdvertisingSetParameters(mConnectable, mScannable, mIsLegacy, mIsAnonymous, |
| mIncludeTxPower, mPrimaryPhy, mSecondaryPhy, mInterval, mTxPowerLevel); |
| } |
| } |
| } |