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 17package android.bluetooth.le; 18 19import android.annotation.SystemApi; 20import android.bluetooth.BluetoothDevice; 21import android.os.Parcel; 22import 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 */ 28public 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 155 public int getScanMode() { 156 return mScanMode; 157 } 158 159 public int getCallbackType() { 160 return mCallbackType; 161 } 162 163 public int getScanResultType() { 164 return mScanResultType; 165 } 166 167 /** 168 * @hide 169 */ 170 public int getMatchMode() { 171 return mMatchMode; 172 } 173 174 /** 175 * @hide 176 */ 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 */ 186 public boolean getLegacy() { 187 return mLegacy; 188 } 189 190 /** 191 * Returns the physical layer used during a scan. 192 */ 193 public int getPhy() { 194 return mPhy; 195 } 196 197 /** 198 * Returns report delay timestamp based on the device clock. 199 */ 200 public long getReportDelayMillis() { 201 return mReportDelayMillis; 202 } 203 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 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 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 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 */ 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 */ 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. 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 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 */ 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 */ 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 */ 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 */ 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 */ 410 public Builder setPhy(int phy) { 411 mPhy = phy; 412 return this; 413 } 414 415 /** 416 * Build {@link ScanSettings}. 417 */ 418 public ScanSettings build() { 419 return new ScanSettings(mScanMode, mCallbackType, mScanResultType, 420 mReportDelayMillis, mMatchMode, 421 mNumOfMatchesPerFilter, mLegacy, mPhy); 422 } 423 } 424} 425