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