1 /* 2 * Copyright (C) 2014 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.bluetooth.le; 18 19 import android.annotation.SystemApi; 20 import android.bluetooth.BluetoothDevice; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 24 /** 25 * Bluetooth LE scan settings are passed to {@link BluetoothLeScanner#startScan} to define the 26 * parameters for the scan. 27 */ 28 public final class ScanSettings implements Parcelable { 29 30 /** 31 * A special Bluetooth LE scan mode. Applications using this scan mode will passively listen for 32 * other scan results without starting BLE scans themselves. 33 */ 34 public static final int SCAN_MODE_OPPORTUNISTIC = -1; 35 36 /** 37 * Perform Bluetooth LE scan in low power mode. This is the default scan mode as it consumes the 38 * least power. 39 */ 40 public static final int SCAN_MODE_LOW_POWER = 0; 41 42 /** 43 * Perform Bluetooth LE scan in balanced power mode. Scan results are returned at a rate that 44 * provides a good trade-off between scan frequency and power consumption. 45 */ 46 public static final int SCAN_MODE_BALANCED = 1; 47 48 /** 49 * Scan using highest duty cycle. It's recommended to only use this mode when the application is 50 * running in the foreground. 51 */ 52 public static final int SCAN_MODE_LOW_LATENCY = 2; 53 54 /** 55 * Trigger a callback for every Bluetooth advertisement found that matches the filter criteria. 56 * If no filter is active, all advertisement packets are reported. 57 */ 58 public static final int CALLBACK_TYPE_ALL_MATCHES = 1; 59 60 /** 61 * A result callback is only triggered for the first advertisement packet received that matches 62 * the filter criteria. 63 */ 64 public static final int CALLBACK_TYPE_FIRST_MATCH = 2; 65 66 /** 67 * Receive a callback when advertisements are no longer received from a device that has been 68 * previously reported by a first match callback. 69 */ 70 public static final int CALLBACK_TYPE_MATCH_LOST = 4; 71 72 73 /** 74 * Determines how many advertisements to match per filter, as this is scarce hw resource 75 */ 76 /** 77 * Match one advertisement per filter 78 */ 79 public static final int MATCH_NUM_ONE_ADVERTISEMENT = 1; 80 81 /** 82 * Match few advertisement per filter, depends on current capability and availibility of 83 * the resources in hw 84 */ 85 public static final int MATCH_NUM_FEW_ADVERTISEMENT = 2; 86 87 /** 88 * Match as many advertisement per filter as hw could allow, depends on current 89 * capability and availibility of the resources in hw 90 */ 91 public static final int MATCH_NUM_MAX_ADVERTISEMENT = 3; 92 93 94 /** 95 * In Aggressive mode, hw will determine a match sooner even with feeble signal strength 96 * and few number of sightings/match in a duration. 97 */ 98 public static final int MATCH_MODE_AGGRESSIVE = 1; 99 100 /** 101 * For sticky mode, higher threshold of signal strength and sightings is required 102 * before reporting by hw 103 */ 104 public static final int MATCH_MODE_STICKY = 2; 105 106 /** 107 * Request full scan results which contain the device, rssi, advertising data, scan response 108 * as well as the scan timestamp. 109 * 110 * @hide 111 */ 112 @SystemApi 113 public static final int SCAN_RESULT_TYPE_FULL = 0; 114 115 /** 116 * Request abbreviated scan results which contain the device, rssi and scan timestamp. 117 * <p> 118 * <b>Note:</b> It is possible for an application to get more scan results than it asked for, if 119 * there are multiple apps using this type. 120 * 121 * @hide 122 */ 123 @SystemApi 124 public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1; 125 126 /** 127 * Use all supported PHYs for scanning. 128 * This will check the controller capabilities, and start 129 * the scan on 1Mbit and LE Coded PHYs if supported, or on 130 * the 1Mbit PHY only. 131 */ 132 public static final int PHY_LE_ALL_SUPPORTED = 255; 133 134 // Bluetooth LE scan mode. 135 private int mScanMode; 136 137 // Bluetooth LE scan callback type 138 private int mCallbackType; 139 140 // Bluetooth LE scan result type 141 private int mScanResultType; 142 143 // Time of delay for reporting the scan result 144 private long mReportDelayMillis; 145 146 private int mMatchMode; 147 148 private int mNumOfMatchesPerFilter; 149 150 // Include only legacy advertising results 151 private boolean mLegacy; 152 153 private int mPhy; 154 getScanMode()155 public int getScanMode() { 156 return mScanMode; 157 } 158 getCallbackType()159 public int getCallbackType() { 160 return mCallbackType; 161 } 162 getScanResultType()163 public int getScanResultType() { 164 return mScanResultType; 165 } 166 167 /** 168 * @hide 169 */ getMatchMode()170 public int getMatchMode() { 171 return mMatchMode; 172 } 173 174 /** 175 * @hide 176 */ getNumOfMatches()177 public int getNumOfMatches() { 178 return mNumOfMatchesPerFilter; 179 } 180 181 /** 182 * Returns whether only legacy advertisements will be returned. 183 * Legacy advertisements include advertisements as specified 184 * by the Bluetooth core specification 4.2 and below. 185 */ getLegacy()186 public boolean getLegacy() { 187 return mLegacy; 188 } 189 190 /** 191 * Returns the physical layer used during a scan. 192 */ getPhy()193 public int getPhy() { 194 return mPhy; 195 } 196 197 /** 198 * Returns report delay timestamp based on the device clock. 199 */ getReportDelayMillis()200 public long getReportDelayMillis() { 201 return mReportDelayMillis; 202 } 203 ScanSettings(int scanMode, int callbackType, int scanResultType, long reportDelayMillis, int matchMode, int numOfMatchesPerFilter, boolean legacy, int phy)204 private ScanSettings(int scanMode, int callbackType, int scanResultType, 205 long reportDelayMillis, int matchMode, 206 int numOfMatchesPerFilter, boolean legacy, int phy) { 207 mScanMode = scanMode; 208 mCallbackType = callbackType; 209 mScanResultType = scanResultType; 210 mReportDelayMillis = reportDelayMillis; 211 mNumOfMatchesPerFilter = numOfMatchesPerFilter; 212 mMatchMode = matchMode; 213 mLegacy = legacy; 214 mPhy = phy; 215 } 216 ScanSettings(Parcel in)217 private ScanSettings(Parcel in) { 218 mScanMode = in.readInt(); 219 mCallbackType = in.readInt(); 220 mScanResultType = in.readInt(); 221 mReportDelayMillis = in.readLong(); 222 mMatchMode = in.readInt(); 223 mNumOfMatchesPerFilter = in.readInt(); 224 mLegacy = in.readInt() != 0 ? true : false; 225 mPhy = in.readInt(); 226 } 227 228 @Override writeToParcel(Parcel dest, int flags)229 public void writeToParcel(Parcel dest, int flags) { 230 dest.writeInt(mScanMode); 231 dest.writeInt(mCallbackType); 232 dest.writeInt(mScanResultType); 233 dest.writeLong(mReportDelayMillis); 234 dest.writeInt(mMatchMode); 235 dest.writeInt(mNumOfMatchesPerFilter); 236 dest.writeInt(mLegacy ? 1 : 0); 237 dest.writeInt(mPhy); 238 } 239 240 @Override describeContents()241 public int describeContents() { 242 return 0; 243 } 244 245 public static final Parcelable.Creator<ScanSettings> 246 CREATOR = new Creator<ScanSettings>() { 247 @Override 248 public ScanSettings[] newArray(int size) { 249 return new ScanSettings[size]; 250 } 251 252 @Override 253 public ScanSettings createFromParcel(Parcel in) { 254 return new ScanSettings(in); 255 } 256 }; 257 258 /** 259 * Builder for {@link ScanSettings}. 260 */ 261 public static final class Builder { 262 private int mScanMode = SCAN_MODE_LOW_POWER; 263 private int mCallbackType = CALLBACK_TYPE_ALL_MATCHES; 264 private int mScanResultType = SCAN_RESULT_TYPE_FULL; 265 private long mReportDelayMillis = 0; 266 private int mMatchMode = MATCH_MODE_AGGRESSIVE; 267 private int mNumOfMatchesPerFilter = MATCH_NUM_MAX_ADVERTISEMENT; 268 private boolean mLegacy = true; 269 private int mPhy = PHY_LE_ALL_SUPPORTED; 270 271 /** 272 * Set scan mode for Bluetooth LE scan. 273 * 274 * @param scanMode The scan mode can be one of {@link ScanSettings#SCAN_MODE_LOW_POWER}, 275 * {@link ScanSettings#SCAN_MODE_BALANCED} or 276 * {@link ScanSettings#SCAN_MODE_LOW_LATENCY}. 277 * @throws IllegalArgumentException If the {@code scanMode} is invalid. 278 */ setScanMode(int scanMode)279 public Builder setScanMode(int scanMode) { 280 if (scanMode < SCAN_MODE_OPPORTUNISTIC || scanMode > SCAN_MODE_LOW_LATENCY) { 281 throw new IllegalArgumentException("invalid scan mode " + scanMode); 282 } 283 mScanMode = scanMode; 284 return this; 285 } 286 287 /** 288 * Set callback type for Bluetooth LE scan. 289 * 290 * @param callbackType The callback type flags for the scan. 291 * @throws IllegalArgumentException If the {@code callbackType} is invalid. 292 */ setCallbackType(int callbackType)293 public Builder setCallbackType(int callbackType) { 294 295 if (!isValidCallbackType(callbackType)) { 296 throw new IllegalArgumentException("invalid callback type - " + callbackType); 297 } 298 mCallbackType = callbackType; 299 return this; 300 } 301 302 // Returns true if the callbackType is valid. isValidCallbackType(int callbackType)303 private boolean isValidCallbackType(int callbackType) { 304 if (callbackType == CALLBACK_TYPE_ALL_MATCHES || 305 callbackType == CALLBACK_TYPE_FIRST_MATCH || 306 callbackType == CALLBACK_TYPE_MATCH_LOST) { 307 return true; 308 } 309 return callbackType == (CALLBACK_TYPE_FIRST_MATCH | CALLBACK_TYPE_MATCH_LOST); 310 } 311 312 /** 313 * Set scan result type for Bluetooth LE scan. 314 * 315 * @param scanResultType Type for scan result, could be either 316 * {@link ScanSettings#SCAN_RESULT_TYPE_FULL} or 317 * {@link ScanSettings#SCAN_RESULT_TYPE_ABBREVIATED}. 318 * @throws IllegalArgumentException If the {@code scanResultType} is invalid. 319 * @hide 320 */ 321 @SystemApi setScanResultType(int scanResultType)322 public Builder setScanResultType(int scanResultType) { 323 if (scanResultType < SCAN_RESULT_TYPE_FULL 324 || scanResultType > SCAN_RESULT_TYPE_ABBREVIATED) { 325 throw new IllegalArgumentException( 326 "invalid scanResultType - " + scanResultType); 327 } 328 mScanResultType = scanResultType; 329 return this; 330 } 331 332 /** 333 * Set report delay timestamp for Bluetooth LE scan. 334 * 335 * @param reportDelayMillis Delay of report in milliseconds. Set to 0 to be notified of 336 * results immediately. Values > 0 causes the scan results to be queued up and 337 * delivered after the requested delay or when the internal buffers fill up. 338 * @throws IllegalArgumentException If {@code reportDelayMillis} < 0. 339 */ setReportDelay(long reportDelayMillis)340 public Builder setReportDelay(long reportDelayMillis) { 341 if (reportDelayMillis < 0) { 342 throw new IllegalArgumentException("reportDelay must be > 0"); 343 } 344 mReportDelayMillis = reportDelayMillis; 345 return this; 346 } 347 348 /** 349 * Set the number of matches for Bluetooth LE scan filters hardware match 350 * 351 * @param numOfMatches The num of matches can be one of 352 * {@link ScanSettings#MATCH_NUM_ONE_ADVERTISEMENT} or 353 * {@link ScanSettings#MATCH_NUM_FEW_ADVERTISEMENT} or 354 * {@link ScanSettings#MATCH_NUM_MAX_ADVERTISEMENT} 355 * @throws IllegalArgumentException If the {@code matchMode} is invalid. 356 */ setNumOfMatches(int numOfMatches)357 public Builder setNumOfMatches(int numOfMatches) { 358 if (numOfMatches < MATCH_NUM_ONE_ADVERTISEMENT 359 || numOfMatches > MATCH_NUM_MAX_ADVERTISEMENT) { 360 throw new IllegalArgumentException("invalid numOfMatches " + numOfMatches); 361 } 362 mNumOfMatchesPerFilter = numOfMatches; 363 return this; 364 } 365 366 /** 367 * Set match mode for Bluetooth LE scan filters hardware match 368 * 369 * @param matchMode The match mode can be one of 370 * {@link ScanSettings#MATCH_MODE_AGGRESSIVE} or 371 * {@link ScanSettings#MATCH_MODE_STICKY} 372 * @throws IllegalArgumentException If the {@code matchMode} is invalid. 373 */ setMatchMode(int matchMode)374 public Builder setMatchMode(int matchMode) { 375 if (matchMode < MATCH_MODE_AGGRESSIVE 376 || matchMode > MATCH_MODE_STICKY) { 377 throw new IllegalArgumentException("invalid matchMode " + matchMode); 378 } 379 mMatchMode = matchMode; 380 return this; 381 } 382 383 /** 384 * Set whether only legacy advertisments should be returned in scan results. 385 * Legacy advertisements include advertisements as specified by the 386 * Bluetooth core specification 4.2 and below. This is true by default 387 * for compatibility with older apps. 388 * 389 * @param legacy true if only legacy advertisements will be returned 390 */ setLegacy(boolean legacy)391 public Builder setLegacy(boolean legacy) { 392 mLegacy = legacy; 393 return this; 394 } 395 396 /** 397 * Set the Physical Layer to use during this scan. 398 * This is used only if {@link ScanSettings.Builder#setLegacy} 399 * is set to false. 400 * {@link android.bluetooth.BluetoothAdapter#isLeCodedPhySupported} 401 * may be used to check whether LE Coded phy is supported by calling 402 * {@link android.bluetooth.BluetoothAdapter#isLeCodedPhySupported}. 403 * Selecting an unsupported phy will result in failure to start scan. 404 * 405 * @param phy Can be one of 406 * {@link BluetoothDevice#PHY_LE_1M}, 407 * {@link BluetoothDevice#PHY_LE_CODED} or 408 * {@link ScanSettings#PHY_LE_ALL_SUPPORTED} 409 */ setPhy(int phy)410 public Builder setPhy(int phy) { 411 mPhy = phy; 412 return this; 413 } 414 415 /** 416 * Build {@link ScanSettings}. 417 */ build()418 public ScanSettings build() { 419 return new ScanSettings(mScanMode, mCallbackType, mScanResultType, 420 mReportDelayMillis, mMatchMode, 421 mNumOfMatchesPerFilter, mLegacy, mPhy); 422 } 423 } 424 } 425