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