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