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.os.Parcel; 21 import android.os.Parcelable; 22 23 /** 24 * Bluetooth LE scan settings are passed to {@link BluetoothLeScanner#startScan} to define the 25 * parameters for the scan. 26 */ 27 public final class ScanSettings implements Parcelable { 28 29 /** 30 * A special Bluetooth LE scan mode. Applications using this scan mode will passively listen for 31 * other scan results without starting BLE scans themselves. 32 */ 33 public static final int SCAN_MODE_OPPORTUNISTIC = -1; 34 35 /** 36 * Perform Bluetooth LE scan in low power mode. This is the default scan mode as it consumes the 37 * least power. 38 */ 39 public static final int SCAN_MODE_LOW_POWER = 0; 40 41 /** 42 * Perform Bluetooth LE scan in balanced power mode. Scan results are returned at a rate that 43 * provides a good trade-off between scan frequency and power consumption. 44 */ 45 public static final int SCAN_MODE_BALANCED = 1; 46 47 /** 48 * Scan using highest duty cycle. It's recommended to only use this mode when the application is 49 * running in the foreground. 50 */ 51 public static final int SCAN_MODE_LOW_LATENCY = 2; 52 53 /** 54 * Trigger a callback for every Bluetooth advertisement found that matches the filter criteria. 55 * If no filter is active, all advertisement packets are reported. 56 */ 57 public static final int CALLBACK_TYPE_ALL_MATCHES = 1; 58 59 /** 60 * A result callback is only triggered for the first advertisement packet received that matches 61 * the filter criteria. 62 */ 63 public static final int CALLBACK_TYPE_FIRST_MATCH = 2; 64 65 /** 66 * Receive a callback when advertisements are no longer received from a device that has been 67 * previously reported by a first match callback. 68 */ 69 public static final int CALLBACK_TYPE_MATCH_LOST = 4; 70 71 72 /** 73 * Determines how many advertisements to match per filter, as this is scarce hw resource 74 */ 75 /** 76 * Match one advertisement per filter 77 */ 78 public static final int MATCH_NUM_ONE_ADVERTISEMENT = 1; 79 80 /** 81 * Match few advertisement per filter, depends on current capability and availibility of 82 * the resources in hw 83 */ 84 public static final int MATCH_NUM_FEW_ADVERTISEMENT = 2; 85 86 /** 87 * Match as many advertisement per filter as hw could allow, depends on current 88 * capability and availibility of the resources in hw 89 */ 90 public static final int MATCH_NUM_MAX_ADVERTISEMENT = 3; 91 92 93 /** 94 * In Aggressive mode, hw will determine a match sooner even with feeble signal strength 95 * and few number of sightings/match in a duration. 96 */ 97 public static final int MATCH_MODE_AGGRESSIVE = 1; 98 99 /** 100 * For sticky mode, higher threshold of signal strength and sightings is required 101 * before reporting by hw 102 */ 103 public static final int MATCH_MODE_STICKY = 2; 104 105 /** 106 * Request full scan results which contain the device, rssi, advertising data, scan response 107 * as well as the scan timestamp. 108 * 109 * @hide 110 */ 111 @SystemApi 112 public static final int SCAN_RESULT_TYPE_FULL = 0; 113 114 /** 115 * Request abbreviated scan results which contain the device, rssi and scan timestamp. 116 * <p> 117 * <b>Note:</b> It is possible for an application to get more scan results than it asked for, if 118 * there are multiple apps using this type. 119 * 120 * @hide 121 */ 122 @SystemApi 123 public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1; 124 125 // Bluetooth LE scan mode. 126 private int mScanMode; 127 128 // Bluetooth LE scan callback type 129 private int mCallbackType; 130 131 // Bluetooth LE scan result type 132 private int mScanResultType; 133 134 // Time of delay for reporting the scan result 135 private long mReportDelayMillis; 136 137 private int mMatchMode; 138 139 private int mNumOfMatchesPerFilter; 140 getScanMode()141 public int getScanMode() { 142 return mScanMode; 143 } 144 getCallbackType()145 public int getCallbackType() { 146 return mCallbackType; 147 } 148 getScanResultType()149 public int getScanResultType() { 150 return mScanResultType; 151 } 152 153 /** 154 * @hide 155 */ getMatchMode()156 public int getMatchMode() { 157 return mMatchMode; 158 } 159 160 /** 161 * @hide 162 */ getNumOfMatches()163 public int getNumOfMatches() { 164 return mNumOfMatchesPerFilter; 165 } 166 167 /** 168 * Returns report delay timestamp based on the device clock. 169 */ getReportDelayMillis()170 public long getReportDelayMillis() { 171 return mReportDelayMillis; 172 } 173 ScanSettings(int scanMode, int callbackType, int scanResultType, long reportDelayMillis, int matchMode, int numOfMatchesPerFilter)174 private ScanSettings(int scanMode, int callbackType, int scanResultType, 175 long reportDelayMillis, int matchMode, int numOfMatchesPerFilter) { 176 mScanMode = scanMode; 177 mCallbackType = callbackType; 178 mScanResultType = scanResultType; 179 mReportDelayMillis = reportDelayMillis; 180 mNumOfMatchesPerFilter = numOfMatchesPerFilter; 181 mMatchMode = matchMode; 182 } 183 ScanSettings(Parcel in)184 private ScanSettings(Parcel in) { 185 mScanMode = in.readInt(); 186 mCallbackType = in.readInt(); 187 mScanResultType = in.readInt(); 188 mReportDelayMillis = in.readLong(); 189 mMatchMode = in.readInt(); 190 mNumOfMatchesPerFilter = in.readInt(); 191 } 192 193 @Override writeToParcel(Parcel dest, int flags)194 public void writeToParcel(Parcel dest, int flags) { 195 dest.writeInt(mScanMode); 196 dest.writeInt(mCallbackType); 197 dest.writeInt(mScanResultType); 198 dest.writeLong(mReportDelayMillis); 199 dest.writeInt(mMatchMode); 200 dest.writeInt(mNumOfMatchesPerFilter); 201 } 202 203 @Override describeContents()204 public int describeContents() { 205 return 0; 206 } 207 208 public static final Parcelable.Creator<ScanSettings> 209 CREATOR = new Creator<ScanSettings>() { 210 @Override 211 public ScanSettings[] newArray(int size) { 212 return new ScanSettings[size]; 213 } 214 215 @Override 216 public ScanSettings createFromParcel(Parcel in) { 217 return new ScanSettings(in); 218 } 219 }; 220 221 /** 222 * Builder for {@link ScanSettings}. 223 */ 224 public static final class Builder { 225 private int mScanMode = SCAN_MODE_LOW_POWER; 226 private int mCallbackType = CALLBACK_TYPE_ALL_MATCHES; 227 private int mScanResultType = SCAN_RESULT_TYPE_FULL; 228 private long mReportDelayMillis = 0; 229 private int mMatchMode = MATCH_MODE_AGGRESSIVE; 230 private int mNumOfMatchesPerFilter = MATCH_NUM_MAX_ADVERTISEMENT; 231 /** 232 * Set scan mode for Bluetooth LE scan. 233 * 234 * @param scanMode The scan mode can be one of {@link ScanSettings#SCAN_MODE_LOW_POWER}, 235 * {@link ScanSettings#SCAN_MODE_BALANCED} or 236 * {@link ScanSettings#SCAN_MODE_LOW_LATENCY}. 237 * @throws IllegalArgumentException If the {@code scanMode} is invalid. 238 */ setScanMode(int scanMode)239 public Builder setScanMode(int scanMode) { 240 if (scanMode < SCAN_MODE_OPPORTUNISTIC || scanMode > SCAN_MODE_LOW_LATENCY) { 241 throw new IllegalArgumentException("invalid scan mode " + scanMode); 242 } 243 mScanMode = scanMode; 244 return this; 245 } 246 247 /** 248 * Set callback type for Bluetooth LE scan. 249 * 250 * @param callbackType The callback type flags for the scan. 251 * @throws IllegalArgumentException If the {@code callbackType} is invalid. 252 */ setCallbackType(int callbackType)253 public Builder setCallbackType(int callbackType) { 254 255 if (!isValidCallbackType(callbackType)) { 256 throw new IllegalArgumentException("invalid callback type - " + callbackType); 257 } 258 mCallbackType = callbackType; 259 return this; 260 } 261 262 // Returns true if the callbackType is valid. isValidCallbackType(int callbackType)263 private boolean isValidCallbackType(int callbackType) { 264 if (callbackType == CALLBACK_TYPE_ALL_MATCHES || 265 callbackType == CALLBACK_TYPE_FIRST_MATCH || 266 callbackType == CALLBACK_TYPE_MATCH_LOST) { 267 return true; 268 } 269 return callbackType == (CALLBACK_TYPE_FIRST_MATCH | CALLBACK_TYPE_MATCH_LOST); 270 } 271 272 /** 273 * Set scan result type for Bluetooth LE scan. 274 * 275 * @param scanResultType Type for scan result, could be either 276 * {@link ScanSettings#SCAN_RESULT_TYPE_FULL} or 277 * {@link ScanSettings#SCAN_RESULT_TYPE_ABBREVIATED}. 278 * @throws IllegalArgumentException If the {@code scanResultType} is invalid. 279 * @hide 280 */ 281 @SystemApi setScanResultType(int scanResultType)282 public Builder setScanResultType(int scanResultType) { 283 if (scanResultType < SCAN_RESULT_TYPE_FULL 284 || scanResultType > SCAN_RESULT_TYPE_ABBREVIATED) { 285 throw new IllegalArgumentException( 286 "invalid scanResultType - " + scanResultType); 287 } 288 mScanResultType = scanResultType; 289 return this; 290 } 291 292 /** 293 * Set report delay timestamp for Bluetooth LE scan. 294 * 295 * @param reportDelayMillis Delay of report in milliseconds. Set to 0 to be notified of 296 * results immediately. Values > 0 causes the scan results to be queued up and 297 * delivered after the requested delay or when the internal buffers fill up. 298 * @throws IllegalArgumentException If {@code reportDelayMillis} < 0. 299 */ setReportDelay(long reportDelayMillis)300 public Builder setReportDelay(long reportDelayMillis) { 301 if (reportDelayMillis < 0) { 302 throw new IllegalArgumentException("reportDelay must be > 0"); 303 } 304 mReportDelayMillis = reportDelayMillis; 305 return this; 306 } 307 308 /** 309 * Set the number of matches for Bluetooth LE scan filters hardware match 310 * 311 * @param numOfMatches The num of matches can be one of 312 * {@link ScanSettings#MATCH_NUM_ONE_ADVERTISEMENT} or 313 * {@link ScanSettings#MATCH_NUM_FEW_ADVERTISEMENT} or 314 * {@link ScanSettings#MATCH_NUM_MAX_ADVERTISEMENT} 315 * @throws IllegalArgumentException If the {@code matchMode} is invalid. 316 */ setNumOfMatches(int numOfMatches)317 public Builder setNumOfMatches(int numOfMatches) { 318 if (numOfMatches < MATCH_NUM_ONE_ADVERTISEMENT 319 || numOfMatches > MATCH_NUM_MAX_ADVERTISEMENT) { 320 throw new IllegalArgumentException("invalid numOfMatches " + numOfMatches); 321 } 322 mNumOfMatchesPerFilter = numOfMatches; 323 return this; 324 } 325 326 /** 327 * Set match mode for Bluetooth LE scan filters hardware match 328 * 329 * @param matchMode The match mode can be one of 330 * {@link ScanSettings#MATCH_MODE_AGGRESSIVE} or 331 * {@link ScanSettings#MATCH_MODE_STICKY} 332 * @throws IllegalArgumentException If the {@code matchMode} is invalid. 333 */ setMatchMode(int matchMode)334 public Builder setMatchMode(int matchMode) { 335 if (matchMode < MATCH_MODE_AGGRESSIVE 336 || matchMode > MATCH_MODE_STICKY) { 337 throw new IllegalArgumentException("invalid matchMode " + matchMode); 338 } 339 mMatchMode = matchMode; 340 return this; 341 } 342 343 /** 344 * Build {@link ScanSettings}. 345 */ build()346 public ScanSettings build() { 347 return new ScanSettings(mScanMode, mCallbackType, mScanResultType, 348 mReportDelayMillis, mMatchMode, mNumOfMatchesPerFilter); 349 } 350 } 351 } 352