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. This mode is enforced if the scanning application is not in foreground. 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 * Perform Bluetooth LE scan in ambient discovery mode. This mode has lower duty cycle and more 56 * aggressive scan interval than balanced mode that provides a good trade-off between scan 57 * latency and power consumption. 58 * 59 * @hide 60 */ 61 @SystemApi 62 public static final int SCAN_MODE_AMBIENT_DISCOVERY = 3; 63 64 /** 65 * Default Bluetooth LE scan mode when the screen is off. 66 * This mode has the low duty cycle and long scan interval which results in the lowest 67 * power consumption among all modes. It is for the framework internal use only. 68 * 69 * @hide 70 */ 71 public static final int SCAN_MODE_SCREEN_OFF = 4; 72 73 /** 74 * Balanced Bluetooth LE scan mode for foreground service when the screen is off. 75 * It is for the framework internal use only. 76 * 77 * @hide 78 */ 79 public static final int SCAN_MODE_SCREEN_OFF_BALANCED = 5; 80 81 /** 82 * Trigger a callback for every Bluetooth advertisement found that matches the filter criteria. 83 * If no filter is active, all advertisement packets are reported. 84 */ 85 public static final int CALLBACK_TYPE_ALL_MATCHES = 1; 86 87 /** 88 * A result callback is only triggered for the first advertisement packet received that matches 89 * the filter criteria. 90 */ 91 public static final int CALLBACK_TYPE_FIRST_MATCH = 2; 92 93 /** 94 * Receive a callback when advertisements are no longer received from a device that has been 95 * previously reported by a first match callback. 96 */ 97 public static final int CALLBACK_TYPE_MATCH_LOST = 4; 98 99 /** 100 * A result callback for every Bluetooth advertisement found that matches the filter criteria 101 * is only triggered when screen is turned on. While the screen is turned off, the 102 * advertisements are batched and the batched result callbacks are triggered every report delay. 103 * When the batch scan with this callback type is activated, the batched result callbacks are 104 * also triggered while turning on screen or disabling the scan. This callback type must be used 105 * with a report delay of {@link ScanSettings#AUTO_BATCH_MIN_REPORT_DELAY_MILLIS} or greater. 106 */ 107 public static final int CALLBACK_TYPE_ALL_MATCHES_AUTO_BATCH = 8; 108 109 /** 110 * Minimum report delay for {@link ScanSettings#CALLBACK_TYPE_ALL_MATCHES_AUTO_BATCH}. 111 */ 112 public static final long AUTO_BATCH_MIN_REPORT_DELAY_MILLIS = 1000 * 60 * 10; 113 114 /** 115 * Determines how many advertisements to match per filter, as this is scarce hw resource. 116 * Match one advertisement per filter. 117 */ 118 public static final int MATCH_NUM_ONE_ADVERTISEMENT = 1; 119 120 /** 121 * Match few advertisement per filter, depends on current capability and availability of 122 * the resources in hw. 123 */ 124 public static final int MATCH_NUM_FEW_ADVERTISEMENT = 2; 125 126 /** 127 * Match as many advertisement per filter as hw could allow, depends on current 128 * capability and availability of the resources in hw. 129 */ 130 public static final int MATCH_NUM_MAX_ADVERTISEMENT = 3; 131 132 133 /** 134 * In Aggressive mode, hw will determine a match sooner even with feeble signal strength 135 * and few number of sightings/match in a duration. 136 */ 137 public static final int MATCH_MODE_AGGRESSIVE = 1; 138 139 /** 140 * For sticky mode, higher threshold of signal strength and sightings is required 141 * before reporting by hw. 142 */ 143 public static final int MATCH_MODE_STICKY = 2; 144 145 /** 146 * Request full scan results which contain the device, rssi, advertising data, scan response 147 * as well as the scan timestamp. 148 * 149 * @hide 150 */ 151 @SystemApi 152 public static final int SCAN_RESULT_TYPE_FULL = 0; 153 154 /** 155 * Request abbreviated scan results which contain the device, rssi and scan timestamp. 156 * <p> 157 * <b>Note:</b> It is possible for an application to get more scan results than it asked for, if 158 * there are multiple apps using this type. 159 * 160 * @hide 161 */ 162 @SystemApi 163 public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1; 164 165 /** 166 * Use all supported PHYs for scanning. 167 * This will check the controller capabilities, and start 168 * the scan on 1Mbit and LE Coded PHYs if supported, or on 169 * the 1Mbit PHY only. 170 */ 171 public static final int PHY_LE_ALL_SUPPORTED = 255; 172 173 // Bluetooth LE scan mode. 174 private int mScanMode; 175 176 // Bluetooth LE scan callback type. 177 private int mCallbackType; 178 179 // Bluetooth LE scan result type. 180 private int mScanResultType; 181 182 // Time of delay for reporting the scan result. 183 private long mReportDelayMillis; 184 185 private int mMatchMode; 186 187 private int mNumOfMatchesPerFilter; 188 189 // Include only legacy advertising results. 190 private boolean mLegacy; 191 192 private int mPhy; 193 getScanMode()194 public int getScanMode() { 195 return mScanMode; 196 } 197 getCallbackType()198 public int getCallbackType() { 199 return mCallbackType; 200 } 201 getScanResultType()202 public int getScanResultType() { 203 return mScanResultType; 204 } 205 206 /** 207 * @hide 208 */ getMatchMode()209 public int getMatchMode() { 210 return mMatchMode; 211 } 212 213 /** 214 * @hide 215 */ getNumOfMatches()216 public int getNumOfMatches() { 217 return mNumOfMatchesPerFilter; 218 } 219 220 /** 221 * Returns whether only legacy advertisements will be returned. 222 * Legacy advertisements include advertisements as specified 223 * by the Bluetooth core specification 4.2 and below. 224 */ getLegacy()225 public boolean getLegacy() { 226 return mLegacy; 227 } 228 229 /** 230 * Returns the physical layer used during a scan. 231 */ getPhy()232 public int getPhy() { 233 return mPhy; 234 } 235 236 /** 237 * Returns report delay timestamp based on the device clock. 238 */ getReportDelayMillis()239 public long getReportDelayMillis() { 240 return mReportDelayMillis; 241 } 242 ScanSettings(int scanMode, int callbackType, int scanResultType, long reportDelayMillis, int matchMode, int numOfMatchesPerFilter, boolean legacy, int phy)243 private ScanSettings(int scanMode, int callbackType, int scanResultType, 244 long reportDelayMillis, int matchMode, 245 int numOfMatchesPerFilter, boolean legacy, int phy) { 246 mScanMode = scanMode; 247 mCallbackType = callbackType; 248 mScanResultType = scanResultType; 249 mReportDelayMillis = reportDelayMillis; 250 mNumOfMatchesPerFilter = numOfMatchesPerFilter; 251 mMatchMode = matchMode; 252 mLegacy = legacy; 253 mPhy = phy; 254 } 255 ScanSettings(Parcel in)256 private ScanSettings(Parcel in) { 257 mScanMode = in.readInt(); 258 mCallbackType = in.readInt(); 259 mScanResultType = in.readInt(); 260 mReportDelayMillis = in.readLong(); 261 mMatchMode = in.readInt(); 262 mNumOfMatchesPerFilter = in.readInt(); 263 mLegacy = in.readInt() != 0; 264 mPhy = in.readInt(); 265 } 266 267 @Override writeToParcel(Parcel dest, int flags)268 public void writeToParcel(Parcel dest, int flags) { 269 dest.writeInt(mScanMode); 270 dest.writeInt(mCallbackType); 271 dest.writeInt(mScanResultType); 272 dest.writeLong(mReportDelayMillis); 273 dest.writeInt(mMatchMode); 274 dest.writeInt(mNumOfMatchesPerFilter); 275 dest.writeInt(mLegacy ? 1 : 0); 276 dest.writeInt(mPhy); 277 } 278 279 @Override describeContents()280 public int describeContents() { 281 return 0; 282 } 283 284 public static final @android.annotation.NonNull Parcelable.Creator<ScanSettings> CREATOR = 285 new Creator<ScanSettings>() { 286 @Override 287 public ScanSettings[] newArray(int size) { 288 return new ScanSettings[size]; 289 } 290 291 @Override 292 public ScanSettings createFromParcel(Parcel in) { 293 return new ScanSettings(in); 294 } 295 }; 296 297 /** 298 * Builder for {@link ScanSettings}. 299 */ 300 public static final class Builder { 301 private int mScanMode = SCAN_MODE_LOW_POWER; 302 private int mCallbackType = CALLBACK_TYPE_ALL_MATCHES; 303 private int mScanResultType = SCAN_RESULT_TYPE_FULL; 304 private long mReportDelayMillis = 0; 305 private int mMatchMode = MATCH_MODE_AGGRESSIVE; 306 private int mNumOfMatchesPerFilter = MATCH_NUM_MAX_ADVERTISEMENT; 307 private boolean mLegacy = true; 308 private int mPhy = PHY_LE_ALL_SUPPORTED; 309 310 /** 311 * Set scan mode for Bluetooth LE scan. 312 * 313 * @param scanMode The scan mode can be one of {@link ScanSettings#SCAN_MODE_LOW_POWER}, 314 * {@link ScanSettings#SCAN_MODE_BALANCED} or {@link ScanSettings#SCAN_MODE_LOW_LATENCY}. 315 * @throws IllegalArgumentException If the {@code scanMode} is invalid. 316 */ setScanMode(int scanMode)317 public Builder setScanMode(int scanMode) { 318 switch (scanMode) { 319 case SCAN_MODE_OPPORTUNISTIC: 320 case SCAN_MODE_LOW_POWER: 321 case SCAN_MODE_BALANCED: 322 case SCAN_MODE_LOW_LATENCY: 323 case SCAN_MODE_AMBIENT_DISCOVERY: 324 case SCAN_MODE_SCREEN_OFF: 325 case SCAN_MODE_SCREEN_OFF_BALANCED: 326 mScanMode = scanMode; 327 break; 328 default: 329 throw new IllegalArgumentException("invalid scan mode " + scanMode); 330 } 331 return this; 332 } 333 334 /** 335 * Set callback type for Bluetooth LE scan. 336 * 337 * @param callbackType The callback type flags for the scan. 338 * @throws IllegalArgumentException If the {@code callbackType} is invalid. 339 */ setCallbackType(int callbackType)340 public Builder setCallbackType(int callbackType) { 341 342 if (!isValidCallbackType(callbackType)) { 343 throw new IllegalArgumentException("invalid callback type - " + callbackType); 344 } 345 mCallbackType = callbackType; 346 return this; 347 } 348 349 // Returns true if the callbackType is valid. isValidCallbackType(int callbackType)350 private boolean isValidCallbackType(int callbackType) { 351 if (callbackType == CALLBACK_TYPE_ALL_MATCHES 352 || callbackType == CALLBACK_TYPE_ALL_MATCHES_AUTO_BATCH 353 || callbackType == CALLBACK_TYPE_FIRST_MATCH 354 || callbackType == CALLBACK_TYPE_MATCH_LOST) { 355 return true; 356 } 357 return callbackType == (CALLBACK_TYPE_FIRST_MATCH | CALLBACK_TYPE_MATCH_LOST); 358 } 359 360 /** 361 * Set scan result type for Bluetooth LE scan. 362 * 363 * @param scanResultType Type for scan result, could be either {@link 364 * ScanSettings#SCAN_RESULT_TYPE_FULL} or {@link ScanSettings#SCAN_RESULT_TYPE_ABBREVIATED}. 365 * @throws IllegalArgumentException If the {@code scanResultType} is invalid. 366 * @hide 367 */ 368 @SystemApi setScanResultType(int scanResultType)369 public Builder setScanResultType(int scanResultType) { 370 if (scanResultType < SCAN_RESULT_TYPE_FULL 371 || scanResultType > SCAN_RESULT_TYPE_ABBREVIATED) { 372 throw new IllegalArgumentException( 373 "invalid scanResultType - " + scanResultType); 374 } 375 mScanResultType = scanResultType; 376 return this; 377 } 378 379 /** 380 * Set report delay timestamp for Bluetooth LE scan. If set to 0, you will be notified of 381 * scan results immediately. If > 0, scan results are queued up and delivered after the 382 * requested delay or 5000 milliseconds (whichever is higher). Note scan results may be 383 * delivered sooner if the internal buffers fill up. 384 * 385 * @param reportDelayMillis how frequently scan results should be delivered in 386 * milliseconds 387 * @throws IllegalArgumentException if {@code reportDelayMillis} < 0 388 */ setReportDelay(long reportDelayMillis)389 public Builder setReportDelay(long reportDelayMillis) { 390 if (reportDelayMillis < 0) { 391 throw new IllegalArgumentException("reportDelay must be > 0"); 392 } 393 mReportDelayMillis = reportDelayMillis; 394 return this; 395 } 396 397 /** 398 * Set the number of matches for Bluetooth LE scan filters hardware match. 399 * 400 * @param numOfMatches The num of matches can be one of 401 * {@link ScanSettings#MATCH_NUM_ONE_ADVERTISEMENT} 402 * or {@link ScanSettings#MATCH_NUM_FEW_ADVERTISEMENT} or {@link 403 * ScanSettings#MATCH_NUM_MAX_ADVERTISEMENT} 404 * @throws IllegalArgumentException If the {@code matchMode} is invalid. 405 */ setNumOfMatches(int numOfMatches)406 public Builder setNumOfMatches(int numOfMatches) { 407 if (numOfMatches < MATCH_NUM_ONE_ADVERTISEMENT 408 || numOfMatches > MATCH_NUM_MAX_ADVERTISEMENT) { 409 throw new IllegalArgumentException("invalid numOfMatches " + numOfMatches); 410 } 411 mNumOfMatchesPerFilter = numOfMatches; 412 return this; 413 } 414 415 /** 416 * Set match mode for Bluetooth LE scan filters hardware match. 417 * 418 * @param matchMode The match mode can be one of {@link ScanSettings#MATCH_MODE_AGGRESSIVE} 419 * or {@link ScanSettings#MATCH_MODE_STICKY} 420 * @throws IllegalArgumentException If the {@code matchMode} is invalid. 421 */ setMatchMode(int matchMode)422 public Builder setMatchMode(int matchMode) { 423 if (matchMode < MATCH_MODE_AGGRESSIVE 424 || matchMode > MATCH_MODE_STICKY) { 425 throw new IllegalArgumentException("invalid matchMode " + matchMode); 426 } 427 mMatchMode = matchMode; 428 return this; 429 } 430 431 /** 432 * Set whether only legacy advertisments should be returned in scan results. 433 * Legacy advertisements include advertisements as specified by the 434 * Bluetooth core specification 4.2 and below. This is true by default 435 * for compatibility with older apps. 436 * 437 * @param legacy true if only legacy advertisements will be returned 438 */ setLegacy(boolean legacy)439 public Builder setLegacy(boolean legacy) { 440 mLegacy = legacy; 441 return this; 442 } 443 444 /** 445 * Set the Physical Layer to use during this scan. 446 * This is used only if {@link ScanSettings.Builder#setLegacy} 447 * is set to false. 448 * {@link android.bluetooth.BluetoothAdapter#isLeCodedPhySupported} 449 * may be used to check whether LE Coded phy is supported by calling 450 * {@link android.bluetooth.BluetoothAdapter#isLeCodedPhySupported}. 451 * Selecting an unsupported phy will result in failure to start scan. 452 * 453 * @param phy Can be one of {@link BluetoothDevice#PHY_LE_1M}, {@link 454 * BluetoothDevice#PHY_LE_CODED} or {@link ScanSettings#PHY_LE_ALL_SUPPORTED} 455 */ setPhy(int phy)456 public Builder setPhy(int phy) { 457 mPhy = phy; 458 return this; 459 } 460 461 /** 462 * Build {@link ScanSettings}. 463 * 464 * @throws IllegalArgumentException if the settings cannot be built. 465 */ build()466 public ScanSettings build() { 467 if (mCallbackType == CALLBACK_TYPE_ALL_MATCHES_AUTO_BATCH 468 && mReportDelayMillis < AUTO_BATCH_MIN_REPORT_DELAY_MILLIS) { 469 throw new IllegalArgumentException("report delay for auto batch must be >= " 470 + AUTO_BATCH_MIN_REPORT_DELAY_MILLIS); 471 } 472 return new ScanSettings(mScanMode, mCallbackType, mScanResultType, 473 mReportDelayMillis, mMatchMode, 474 mNumOfMatchesPerFilter, mLegacy, mPhy); 475 } 476 } 477 } 478