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 /** 101 * Determines how many advertisements to match per filter, as this is scarce hw resource 102 */ 103 /** 104 * Match one advertisement per filter 105 */ 106 public static final int MATCH_NUM_ONE_ADVERTISEMENT = 1; 107 108 /** 109 * Match few advertisement per filter, depends on current capability and availibility of 110 * the resources in hw 111 */ 112 public static final int MATCH_NUM_FEW_ADVERTISEMENT = 2; 113 114 /** 115 * Match as many advertisement per filter as hw could allow, depends on current 116 * capability and availibility of the resources in hw 117 */ 118 public static final int MATCH_NUM_MAX_ADVERTISEMENT = 3; 119 120 121 /** 122 * In Aggressive mode, hw will determine a match sooner even with feeble signal strength 123 * and few number of sightings/match in a duration. 124 */ 125 public static final int MATCH_MODE_AGGRESSIVE = 1; 126 127 /** 128 * For sticky mode, higher threshold of signal strength and sightings is required 129 * before reporting by hw 130 */ 131 public static final int MATCH_MODE_STICKY = 2; 132 133 /** 134 * Request full scan results which contain the device, rssi, advertising data, scan response 135 * as well as the scan timestamp. 136 * 137 * @hide 138 */ 139 @SystemApi 140 public static final int SCAN_RESULT_TYPE_FULL = 0; 141 142 /** 143 * Request abbreviated scan results which contain the device, rssi and scan timestamp. 144 * <p> 145 * <b>Note:</b> It is possible for an application to get more scan results than it asked for, if 146 * there are multiple apps using this type. 147 * 148 * @hide 149 */ 150 @SystemApi 151 public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1; 152 153 /** 154 * Use all supported PHYs for scanning. 155 * This will check the controller capabilities, and start 156 * the scan on 1Mbit and LE Coded PHYs if supported, or on 157 * the 1Mbit PHY only. 158 */ 159 public static final int PHY_LE_ALL_SUPPORTED = 255; 160 161 // Bluetooth LE scan mode. 162 private int mScanMode; 163 164 // Bluetooth LE scan callback type 165 private int mCallbackType; 166 167 // Bluetooth LE scan result type 168 private int mScanResultType; 169 170 // Time of delay for reporting the scan result 171 private long mReportDelayMillis; 172 173 private int mMatchMode; 174 175 private int mNumOfMatchesPerFilter; 176 177 // Include only legacy advertising results 178 private boolean mLegacy; 179 180 private int mPhy; 181 getScanMode()182 public int getScanMode() { 183 return mScanMode; 184 } 185 getCallbackType()186 public int getCallbackType() { 187 return mCallbackType; 188 } 189 getScanResultType()190 public int getScanResultType() { 191 return mScanResultType; 192 } 193 194 /** 195 * @hide 196 */ getMatchMode()197 public int getMatchMode() { 198 return mMatchMode; 199 } 200 201 /** 202 * @hide 203 */ getNumOfMatches()204 public int getNumOfMatches() { 205 return mNumOfMatchesPerFilter; 206 } 207 208 /** 209 * Returns whether only legacy advertisements will be returned. 210 * Legacy advertisements include advertisements as specified 211 * by the Bluetooth core specification 4.2 and below. 212 */ getLegacy()213 public boolean getLegacy() { 214 return mLegacy; 215 } 216 217 /** 218 * Returns the physical layer used during a scan. 219 */ getPhy()220 public int getPhy() { 221 return mPhy; 222 } 223 224 /** 225 * Returns report delay timestamp based on the device clock. 226 */ getReportDelayMillis()227 public long getReportDelayMillis() { 228 return mReportDelayMillis; 229 } 230 ScanSettings(int scanMode, int callbackType, int scanResultType, long reportDelayMillis, int matchMode, int numOfMatchesPerFilter, boolean legacy, int phy)231 private ScanSettings(int scanMode, int callbackType, int scanResultType, 232 long reportDelayMillis, int matchMode, 233 int numOfMatchesPerFilter, boolean legacy, int phy) { 234 mScanMode = scanMode; 235 mCallbackType = callbackType; 236 mScanResultType = scanResultType; 237 mReportDelayMillis = reportDelayMillis; 238 mNumOfMatchesPerFilter = numOfMatchesPerFilter; 239 mMatchMode = matchMode; 240 mLegacy = legacy; 241 mPhy = phy; 242 } 243 ScanSettings(Parcel in)244 private ScanSettings(Parcel in) { 245 mScanMode = in.readInt(); 246 mCallbackType = in.readInt(); 247 mScanResultType = in.readInt(); 248 mReportDelayMillis = in.readLong(); 249 mMatchMode = in.readInt(); 250 mNumOfMatchesPerFilter = in.readInt(); 251 mLegacy = in.readInt() != 0; 252 mPhy = in.readInt(); 253 } 254 255 @Override writeToParcel(Parcel dest, int flags)256 public void writeToParcel(Parcel dest, int flags) { 257 dest.writeInt(mScanMode); 258 dest.writeInt(mCallbackType); 259 dest.writeInt(mScanResultType); 260 dest.writeLong(mReportDelayMillis); 261 dest.writeInt(mMatchMode); 262 dest.writeInt(mNumOfMatchesPerFilter); 263 dest.writeInt(mLegacy ? 1 : 0); 264 dest.writeInt(mPhy); 265 } 266 267 @Override describeContents()268 public int describeContents() { 269 return 0; 270 } 271 272 public static final @android.annotation.NonNull Parcelable.Creator<ScanSettings> CREATOR = 273 new Creator<ScanSettings>() { 274 @Override 275 public ScanSettings[] newArray(int size) { 276 return new ScanSettings[size]; 277 } 278 279 @Override 280 public ScanSettings createFromParcel(Parcel in) { 281 return new ScanSettings(in); 282 } 283 }; 284 285 /** 286 * Builder for {@link ScanSettings}. 287 */ 288 public static final class Builder { 289 private int mScanMode = SCAN_MODE_LOW_POWER; 290 private int mCallbackType = CALLBACK_TYPE_ALL_MATCHES; 291 private int mScanResultType = SCAN_RESULT_TYPE_FULL; 292 private long mReportDelayMillis = 0; 293 private int mMatchMode = MATCH_MODE_AGGRESSIVE; 294 private int mNumOfMatchesPerFilter = MATCH_NUM_MAX_ADVERTISEMENT; 295 private boolean mLegacy = true; 296 private int mPhy = PHY_LE_ALL_SUPPORTED; 297 298 /** 299 * Set scan mode for Bluetooth LE scan. 300 * 301 * @param scanMode The scan mode can be one of {@link ScanSettings#SCAN_MODE_LOW_POWER}, 302 * {@link ScanSettings#SCAN_MODE_BALANCED} or {@link 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_FIRST_MATCH 341 || callbackType == CALLBACK_TYPE_MATCH_LOST) { 342 return true; 343 } 344 return callbackType == (CALLBACK_TYPE_FIRST_MATCH | CALLBACK_TYPE_MATCH_LOST); 345 } 346 347 /** 348 * Set scan result type for Bluetooth LE scan. 349 * 350 * @param scanResultType Type for scan result, could be either {@link 351 * ScanSettings#SCAN_RESULT_TYPE_FULL} or {@link ScanSettings#SCAN_RESULT_TYPE_ABBREVIATED}. 352 * @throws IllegalArgumentException If the {@code scanResultType} is invalid. 353 * @hide 354 */ 355 @SystemApi setScanResultType(int scanResultType)356 public Builder setScanResultType(int scanResultType) { 357 if (scanResultType < SCAN_RESULT_TYPE_FULL 358 || scanResultType > SCAN_RESULT_TYPE_ABBREVIATED) { 359 throw new IllegalArgumentException( 360 "invalid scanResultType - " + scanResultType); 361 } 362 mScanResultType = scanResultType; 363 return this; 364 } 365 366 /** 367 * Set report delay timestamp for Bluetooth LE scan. If set to 0, you will be notified of 368 * scan results immediately. If > 0, scan results are queued up and delivered after the 369 * requested delay or 5000 milliseconds (whichever is higher). Note scan results may be 370 * delivered sooner if the internal buffers fill up. 371 * 372 * @param reportDelayMillis how frequently scan results should be delivered in 373 * 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 388 * {@link ScanSettings#MATCH_NUM_ONE_ADVERTISEMENT} 389 * or {@link 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 411 || matchMode > MATCH_MODE_STICKY) { 412 throw new IllegalArgumentException("invalid matchMode " + matchMode); 413 } 414 mMatchMode = matchMode; 415 return this; 416 } 417 418 /** 419 * Set whether only legacy advertisments should be returned in scan results. 420 * Legacy advertisements include advertisements as specified by the 421 * Bluetooth core specification 4.2 and below. This is true by default 422 * for compatibility with older apps. 423 * 424 * @param legacy true if only legacy advertisements will be returned 425 */ setLegacy(boolean legacy)426 public Builder setLegacy(boolean legacy) { 427 mLegacy = legacy; 428 return this; 429 } 430 431 /** 432 * Set the Physical Layer to use during this scan. 433 * This is used only if {@link ScanSettings.Builder#setLegacy} 434 * is set to false. 435 * {@link android.bluetooth.BluetoothAdapter#isLeCodedPhySupported} 436 * may be used to check whether LE Coded phy is supported by calling 437 * {@link android.bluetooth.BluetoothAdapter#isLeCodedPhySupported}. 438 * Selecting an unsupported phy will result in failure to start scan. 439 * 440 * @param phy Can be one of {@link BluetoothDevice#PHY_LE_1M}, {@link 441 * BluetoothDevice#PHY_LE_CODED} or {@link ScanSettings#PHY_LE_ALL_SUPPORTED} 442 */ setPhy(int phy)443 public Builder setPhy(int phy) { 444 mPhy = phy; 445 return this; 446 } 447 448 /** 449 * Build {@link ScanSettings}. 450 */ build()451 public ScanSettings build() { 452 return new ScanSettings(mScanMode, mCallbackType, mScanResultType, 453 mReportDelayMillis, mMatchMode, 454 mNumOfMatchesPerFilter, mLegacy, mPhy); 455 } 456 } 457 } 458