Onfound onlost feature.
Change-Id: I5475cb21183abab8cf04af486ff7692396801b92
Signed-off-by: Prerepa Viswanadham <dham@google.com>
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index ee055a5..0442d09 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -998,6 +998,24 @@
}
/**
+ * Return true if hardware has entries available for matching beacons
+ *
+ * @return true if there are hw entries available for matching beacons
+ * @hide
+ */
+ public boolean isHardwareTrackingFiltersAvailable() {
+ if (getState() != STATE_ON) return false;
+ try {
+ synchronized(mManagerCallback) {
+ if(mService != null) return (mService.numOfHwTrackFiltersAvailable() != 0);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ return false;
+ }
+
+ /**
* Return the record of {@link BluetoothActivityEnergyInfo} object that
* has the activity and energy info. This can be used to ascertain what
* the controller has been up to, since the last sample.
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index dabb1ce..299f4c8 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -98,6 +98,7 @@
boolean isActivityAndEnergyReportingSupported();
void getActivityEnergyInfoFromController();
BluetoothActivityEnergyInfo reportActivityInfo();
+ int numOfHwTrackFiltersAvailable();
// for dumpsys support
String dump();
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index 93ea299..73a1907 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -128,6 +128,16 @@
ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED);
return;
}
+ if (!isHardwareResourcesAvailableForScan(settings)) {
+ postCallbackError(callback,
+ ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES);
+ return;
+ }
+ if (!isSettingsAndFilterComboAllowed(settings, filters)) {
+ postCallbackError(callback,
+ ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED);
+ return;
+ }
BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters,
settings, callback, resultStorages);
wrapper.startRegisteration();
@@ -394,4 +404,33 @@
}
return false;
}
+
+ private boolean isSettingsAndFilterComboAllowed(ScanSettings settings,
+ List <ScanFilter> filterList) {
+ final int callbackType = settings.getCallbackType();
+ // If onlost/onfound is requested, a non-empty filter is expected
+ if ((callbackType & ScanSettings.CALLBACK_TYPE_FIRST_MATCH
+ | ScanSettings.CALLBACK_TYPE_MATCH_LOST) != 0) {
+ if (filterList == null) {
+ return false;
+ }
+ for (ScanFilter filter : filterList) {
+ if (filter.isAllFieldsEmpty()) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private boolean isHardwareResourcesAvailableForScan(ScanSettings settings) {
+ final int callbackType = settings.getCallbackType();
+ if ((callbackType & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0
+ || (callbackType & ScanSettings.CALLBACK_TYPE_MATCH_LOST) != 0) {
+ // For onlost/onfound, we required hw support be available
+ return (mBluetoothAdapter.isOffloadedFilteringSupported() &&
+ mBluetoothAdapter.isHardwareTrackingFiltersAvailable());
+ }
+ return true;
+ }
}
diff --git a/core/java/android/bluetooth/le/ScanCallback.java b/core/java/android/bluetooth/le/ScanCallback.java
index 05782a8..27b96bd 100644
--- a/core/java/android/bluetooth/le/ScanCallback.java
+++ b/core/java/android/bluetooth/le/ScanCallback.java
@@ -45,10 +45,16 @@
public static final int SCAN_FAILED_FEATURE_UNSUPPORTED = 4;
/**
+ * Fails to start scan as it is out of hardware resources.
+ * @hide
+ */
+ public static final int SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES = 5;
+
+ /**
* Callback when a BLE advertisement has been found.
*
- * @param callbackType Determines how this callback was triggered. Currently could only be
- * {@link ScanSettings#CALLBACK_TYPE_ALL_MATCHES}.
+ * @param callbackType Determines how this callback was triggered. Could be of
+ * {@link ScanSettings#CALLBACK_TYPE_ALL_MATCHES}
* @param result A Bluetooth LE scan result.
*/
public void onScanResult(int callbackType, ScanResult result) {
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 5025218..92a3817 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -67,6 +67,8 @@
private final byte[] mManufacturerData;
@Nullable
private final byte[] mManufacturerDataMask;
+ private static final ScanFilter EMPTY = new ScanFilter.Builder().build() ;
+
private ScanFilter(String name, String deviceAddress, ParcelUuid uuid,
ParcelUuid uuidMask, ParcelUuid serviceDataUuid,
@@ -410,6 +412,14 @@
}
/**
+ * Checks if the scanfilter is empty
+ * @hide
+ */
+ public boolean isAllFieldsEmpty() {
+ return EMPTY.equals(this);
+ }
+
+ /**
* Builder class for {@link ScanFilter}.
*/
public static final class Builder {
diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java
index 0106686..f103cae 100644
--- a/core/java/android/bluetooth/le/ScanSettings.java
+++ b/core/java/android/bluetooth/le/ScanSettings.java
@@ -59,7 +59,6 @@
/**
* A result callback is only triggered for the first advertisement packet received that matches
* the filter criteria.
- *
* @hide
*/
@SystemApi
@@ -68,15 +67,53 @@
/**
* Receive a callback when advertisements are no longer received from a device that has been
* previously reported by a first match callback.
- *
* @hide
*/
@SystemApi
public static final int CALLBACK_TYPE_MATCH_LOST = 4;
+
/**
- * Request full scan results which contain the device, rssi, advertising data, scan response as
- * well as the scan timestamp.
+ * Determines how many advertisements to match per filter, as this is scarce hw resource
+ */
+ /**
+ * Match one advertisement per filter
+ * @hide
+ */
+ public static final int MATCH_NUM_ONE_ADVERTISEMENT = 1;
+
+ /**
+ * Match few advertisement per filter, depends on current capability and availibility of
+ * the resources in hw
+ * @hide
+ */
+ public static final int MATCH_NUM_FEW_ADVERTISEMENT = 2;
+
+ /**
+ * Match as many advertisement per filter as hw could allow, depends on current
+ * capability and availibility of the resources in hw
+ * @hide
+ */
+ public static final int MATCH_NUM_MAX_ADVERTISEMENT = 3;
+
+
+ /**
+ * In Aggressive mode, hw will determine a match sooner even with feeble signal strength
+ * and few number of sightings/match in a duration.
+ * @hide
+ */
+ public static final int MATCH_MODE_AGGRESSIVE = 1;
+
+ /**
+ * For sticky mode, higher threshold of signal strength and sightings is required
+ * before reporting by hw
+ * @hide
+ */
+ public static final int MATCH_MODE_STICKY = 2;
+
+ /**
+ * Request full scan results which contain the device, rssi, advertising data, scan response
+ * as well as the scan timestamp.
*
* @hide
*/
@@ -106,6 +143,10 @@
// Time of delay for reporting the scan result
private long mReportDelayMillis;
+ private int mMatchMode;
+
+ private int mNumOfMatchesPerFilter;
+
public int getScanMode() {
return mScanMode;
}
@@ -119,6 +160,20 @@
}
/**
+ * @hide
+ */
+ public int getMatchMode() {
+ return mMatchMode;
+ }
+
+ /**
+ * @hide
+ */
+ public int getNumOfMatches() {
+ return mNumOfMatchesPerFilter;
+ }
+
+ /**
* Returns report delay timestamp based on the device clock.
*/
public long getReportDelayMillis() {
@@ -126,11 +181,13 @@
}
private ScanSettings(int scanMode, int callbackType, int scanResultType,
- long reportDelayMillis) {
+ long reportDelayMillis, int matchMode, int numOfMatchesPerFilter) {
mScanMode = scanMode;
mCallbackType = callbackType;
mScanResultType = scanResultType;
mReportDelayMillis = reportDelayMillis;
+ mNumOfMatchesPerFilter = numOfMatchesPerFilter;
+ mMatchMode = numOfMatchesPerFilter;
}
private ScanSettings(Parcel in) {
@@ -138,6 +195,8 @@
mCallbackType = in.readInt();
mScanResultType = in.readInt();
mReportDelayMillis = in.readLong();
+ mMatchMode = in.readInt();
+ mNumOfMatchesPerFilter = in.readInt();
}
@Override
@@ -146,6 +205,8 @@
dest.writeInt(mCallbackType);
dest.writeInt(mScanResultType);
dest.writeLong(mReportDelayMillis);
+ dest.writeInt(mMatchMode);
+ dest.writeInt(mNumOfMatchesPerFilter);
}
@Override
@@ -174,7 +235,8 @@
private int mCallbackType = CALLBACK_TYPE_ALL_MATCHES;
private int mScanResultType = SCAN_RESULT_TYPE_FULL;
private long mReportDelayMillis = 0;
-
+ private int mMatchMode = MATCH_MODE_AGGRESSIVE;
+ private int mNumOfMatchesPerFilter = MATCH_NUM_ONE_ADVERTISEMENT;
/**
* Set scan mode for Bluetooth LE scan.
*
@@ -255,11 +317,48 @@
}
/**
+ * Set the number of matches for Bluetooth LE scan filters hardware match
+ *
+ * @param numOfMatches The num of matches can be one of
+ * {@link ScanSettings#MATCH_NUM_ONE_ADVERTISEMENT} or
+ * {@link ScanSettings#MATCH_NUM_FEW_ADVERTISEMENT} or
+ * {@link ScanSettings#MATCH_NUM_MAX_ADVERTISEMENT}
+ * @throws IllegalArgumentException If the {@code matchMode} is invalid.
+ * @hide
+ */
+ public Builder setNumOfMatches(int numOfMatches) {
+ if (numOfMatches < MATCH_NUM_ONE_ADVERTISEMENT
+ || numOfMatches > MATCH_NUM_MAX_ADVERTISEMENT) {
+ throw new IllegalArgumentException("invalid numOfMatches " + numOfMatches);
+ }
+ mNumOfMatchesPerFilter = numOfMatches;
+ return this;
+ }
+
+ /**
+ * Set match mode for Bluetooth LE scan filters hardware match
+ *
+ * @param matchMode The match mode can be one of
+ * {@link ScanSettings#MATCH_MODE_AGGRESSIVE} or
+ * {@link ScanSettings#MATCH_MODE_STICKY}
+ * @throws IllegalArgumentException If the {@code matchMode} is invalid.
+ * @hide
+ */
+ public Builder setMatchMode(int matchMode) {
+ if (matchMode < MATCH_MODE_AGGRESSIVE
+ || matchMode > MATCH_MODE_STICKY) {
+ throw new IllegalArgumentException("invalid matchMode " + matchMode);
+ }
+ mMatchMode = matchMode;
+ return this;
+ }
+
+ /**
* Build {@link ScanSettings}.
*/
public ScanSettings build() {
return new ScanSettings(mScanMode, mCallbackType, mScanResultType,
- mReportDelayMillis);
+ mReportDelayMillis, mMatchMode, mNumOfMatchesPerFilter);
}
}
}