Loading android/app/src/com/android/bluetooth/gatt/GattService.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -43,6 +43,7 @@ import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.btservice.ProfileService; import java.util.ArrayList; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Collections; import java.util.HashMap; import java.util.HashMap; import java.util.HashSet; import java.util.HashSet; Loading Loading @@ -595,6 +596,7 @@ public class GattService extends ProfileService { if (client.filters == null || client.filters.isEmpty()) { if (client.filters == null || client.filters.isEmpty()) { return true; return true; } } if (DBG) Log.d(TAG, "result: " + scanResult.toString()); for (ScanFilter filter : client.filters) { for (ScanFilter filter : client.filters) { if (DBG) Log.d(TAG, "filter: " + filter.toString()); if (DBG) Log.d(TAG, "filter: " + filter.toString()); if (filter.matches(scanResult)) { if (filter.matches(scanResult)) { Loading Loading @@ -954,6 +956,9 @@ public class GattService extends ProfileService { ClientMap.App app = mClientMap.getById(clientIf); ClientMap.App app = mClientMap.getById(clientIf); if (app == null) return; if (app == null) return; Set<ScanResult> results = parseBatchScanResults(numRecords, reportType, recordData); Set<ScanResult> results = parseBatchScanResults(numRecords, reportType, recordData); for (ScanResult result : new ArrayList<ScanResult>(results)) { Log.d(TAG, result.getScanRecord().toString()); } app.callback.onBatchScanResults(new ArrayList<ScanResult>(results)); app.callback.onBatchScanResults(new ArrayList<ScanResult>(results)); } } Loading Loading @@ -994,6 +999,7 @@ public class GattService extends ProfileService { } } private Set<ScanResult> parseFullResults(int numRecords, byte[] batchRecord) { private Set<ScanResult> parseFullResults(int numRecords, byte[] batchRecord) { Log.d(TAG, "Batch record : " + Arrays.toString(batchRecord)); Set<ScanResult> results = new HashSet<ScanResult>(numRecords); Set<ScanResult> results = new HashSet<ScanResult>(numRecords); int position = 0; int position = 0; while (position < batchRecord.length) { while (position < batchRecord.length) { Loading @@ -1019,6 +1025,7 @@ public class GattService extends ProfileService { System.arraycopy(advertiseBytes, 0, scanRecord, 0, advertisePacketLen); System.arraycopy(advertiseBytes, 0, scanRecord, 0, advertisePacketLen); System.arraycopy(scanResponseBytes, 0, scanRecord, System.arraycopy(scanResponseBytes, 0, scanRecord, advertisePacketLen, scanResponsePacketLen); advertisePacketLen, scanResponsePacketLen); Log.d(TAG, "ScanRecord : " + Arrays.toString(scanRecord)); results.add(new ScanResult(device, ScanRecord.parseFromBytes(scanRecord), results.add(new ScanResult(device, ScanRecord.parseFromBytes(scanRecord), rssi, timestampNanos)); rssi, timestampNanos)); } } Loading android/app/src/com/android/bluetooth/gatt/ScanFilterQueue.java +50 −3 Original line number Original line Diff line number Diff line Loading @@ -16,7 +16,10 @@ package com.android.bluetooth.gatt; package com.android.bluetooth.gatt; import android.bluetooth.BluetoothUuid; import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanFilter; import android.os.ParcelUuid; import android.util.Log; import java.util.Arrays; import java.util.Arrays; import java.util.HashSet; import java.util.HashSet; Loading @@ -32,11 +35,15 @@ import java.util.UUID; */ */ /* package */class ScanFilterQueue { /* package */class ScanFilterQueue { public static final int TYPE_DEVICE_ADDRESS = 0; public static final int TYPE_DEVICE_ADDRESS = 0; public static final int TYPE_SERVICE_DATA = 1; public static final int TYPE_SERVICE_DATA_CHANGED = 1; public static final int TYPE_SERVICE_UUID = 2; public static final int TYPE_SERVICE_UUID = 2; public static final int TYPE_SOLICIT_UUID = 3; public static final int TYPE_SOLICIT_UUID = 3; public static final int TYPE_LOCAL_NAME = 4; public static final int TYPE_LOCAL_NAME = 4; public static final int TYPE_MANUFACTURER_DATA = 5; public static final int TYPE_MANUFACTURER_DATA = 5; public static final int TYPE_SERVICE_DATA = 6; // Max length is 31 - 3(flags) - 2 (one byte for length and one byte for type). private static final int MAX_LEN_PER_FIELD = 26; // Values defined in bluedroid. // Values defined in bluedroid. private static final byte DEVICE_TYPE_ALL = 0; private static final byte DEVICE_TYPE_ALL = 0; Loading Loading @@ -91,7 +98,7 @@ import java.util.UUID; void addServiceChanged() { void addServiceChanged() { Entry entry = new Entry(); Entry entry = new Entry(); entry.type = TYPE_SERVICE_DATA; entry.type = TYPE_SERVICE_DATA_CHANGED; mEntries.add(entry); mEntries.add(entry); } } Loading Loading @@ -146,6 +153,14 @@ import java.util.UUID; mEntries.add(entry); mEntries.add(entry); } } void addServiceData(byte[] data, byte[] dataMask) { Entry entry = new Entry(); entry.type = TYPE_SERVICE_DATA; entry.data = data; entry.data_mask = dataMask; mEntries.add(entry); } Entry pop() { Entry pop() { if (isEmpty()) { if (isEmpty()) { return null; return null; Loading Loading @@ -178,7 +193,6 @@ import java.util.UUID; int getFeatureSelection() { int getFeatureSelection() { int selc = 0; int selc = 0; for (Entry entry : mEntries) { for (Entry entry : mEntries) { System.out.println("entry selc value " + (1 << entry.type)); selc |= (1 << entry.type); selc |= (1 << entry.type); } } return selc; return selc; Loading Loading @@ -212,5 +226,38 @@ import java.util.UUID; filter.getManufacturerData(), filter.getManufacturerDataMask()); filter.getManufacturerData(), filter.getManufacturerDataMask()); } } } } if (filter.getServiceDataUuid() != null && filter.getServiceData() != null) { ParcelUuid serviceDataUuid = filter.getServiceDataUuid(); byte[] serviceData = filter.getServiceData(); byte[] serviceDataMask = filter.getServiceDataMask(); if (serviceDataMask == null) { serviceDataMask = new byte[serviceData.length]; Arrays.fill(serviceDataMask, (byte) 0xFF); } serviceData = concate(serviceDataUuid, serviceData); serviceDataMask = concate(serviceDataUuid, serviceDataMask); if (serviceData != null && serviceDataMask != null) { addServiceData(serviceData, serviceDataMask); } } } private byte[] concate(ParcelUuid serviceDataUuid, byte[] serviceData) { int dataLen = 2 + (serviceData == null ? 0 : serviceData.length); // If data is too long, don't add it to hardware scan filter. if (dataLen > MAX_LEN_PER_FIELD) { return null; } byte[] concated = new byte[dataLen]; // Extract 16 bit UUID value. int uuidValue = BluetoothUuid.getServiceIdentifierFromParcelUuid( serviceDataUuid); // First two bytes are service data UUID in little-endian. concated[0] = (byte) (uuidValue & 0xFF); concated[1] = (byte) ((uuidValue >> 8) & 0xFF); if (serviceData != null) { System.arraycopy(serviceData, 0, concated, 2, serviceData.length); } return concated; } } } } android/app/src/com/android/bluetooth/gatt/ScanManager.java +70 −7 Original line number Original line Diff line number Diff line Loading @@ -16,13 +16,20 @@ package com.android.bluetooth.gatt; package com.android.bluetooth.gatt; import android.app.AlarmManager; import android.app.PendingIntent; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter; import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanSettings; import android.bluetooth.le.ScanSettings; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; import android.os.Handler; import android.os.HandlerThread; import android.os.HandlerThread; import android.os.Looper; import android.os.Looper; import android.os.Message; import android.os.Message; import android.os.SystemClock; import android.util.Log; import android.util.Log; import com.android.bluetooth.Utils; import com.android.bluetooth.Utils; Loading Loading @@ -57,6 +64,9 @@ public class ScanManager { private static final int MSG_STOP_BLE_SCAN = 1; private static final int MSG_STOP_BLE_SCAN = 1; private static final int MSG_FLUSH_BATCH_RESULTS = 2; private static final int MSG_FLUSH_BATCH_RESULTS = 2; private static final String ACTION_REFRESH_BATCHED_SCAN = "com.android.bluetooth.gatt.REFRESH_BATCHED_SCAN"; // Timeout for each controller operation. // Timeout for each controller operation. private static final int OPERATION_TIME_OUT_MILLIS = 500; private static final int OPERATION_TIME_OUT_MILLIS = 500; Loading @@ -72,8 +82,8 @@ public class ScanManager { ScanManager(GattService service) { ScanManager(GattService service) { mRegularScanClients = new HashSet<ScanClient>(); mRegularScanClients = new HashSet<ScanClient>(); mBatchClients = new HashSet<ScanClient>(); mBatchClients = new HashSet<ScanClient>(); mScanNative = new ScanNative(); mService = service; mService = service; mScanNative = new ScanNative(); } } void start() { void start() { Loading @@ -85,6 +95,7 @@ public class ScanManager { void cleanup() { void cleanup() { mRegularScanClients.clear(); mRegularScanClients.clear(); mBatchClients.clear(); mBatchClients.clear(); mScanNative.cleanup(); } } /** /** Loading Loading @@ -236,10 +247,34 @@ public class ScanManager { private final Deque<Integer> mFilterIndexStack; private final Deque<Integer> mFilterIndexStack; // Map of clientIf and Filter indices used by client. // Map of clientIf and Filter indices used by client. private final Map<Integer, Deque<Integer>> mClientFilterIndexMap; private final Map<Integer, Deque<Integer>> mClientFilterIndexMap; private AlarmManager mAlarmManager; private PendingIntent mBatchScanIntervalIntent; ScanNative() { ScanNative() { mFilterIndexStack = new ArrayDeque<Integer>(); mFilterIndexStack = new ArrayDeque<Integer>(); mClientFilterIndexMap = new HashMap<Integer, Deque<Integer>>(); mClientFilterIndexMap = new HashMap<Integer, Deque<Integer>>(); mAlarmManager = (AlarmManager) mService.getSystemService(Context.ALARM_SERVICE); Intent batchIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null); mBatchScanIntervalIntent = PendingIntent.getBroadcast(mService, 0, batchIntent, 0); IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_REFRESH_BATCHED_SCAN); mService.registerReceiver( new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.d(TAG, "awakened up at time " + SystemClock.elapsedRealtime()); String action = intent.getAction(); if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) { if (mBatchClients.isEmpty()) { return; } // TODO: find out if we need to flush all clients at once. flushBatchScanResults(mBatchClients.iterator().next()); } } }, filter); } } private void resetCountDownLatch() { private void resetCountDownLatch() { Loading Loading @@ -286,10 +321,24 @@ public class ScanManager { int scanWindowUnit = 8; int scanWindowUnit = 8; int discardRule = 2; int discardRule = 2; int addressType = 0; int addressType = 0; logd("Starting BLE batch scan"); gattClientStartBatchScanNative(client.clientIf, scanMode, scanIntervalUnit, gattClientStartBatchScanNative(client.clientIf, scanMode, scanIntervalUnit, scanWindowUnit, scanWindowUnit, addressType, discardRule); addressType, logd("Starting BLE batch scan, scanMode -" + scanMode); discardRule); gattClientStartBatchScanNative(client.clientIf, scanMode, scanIntervalUnit, scanWindowUnit, addressType, discardRule); setBatchAlarm(); } private void setBatchAlarm() { if (mBatchClients.isEmpty()) { mAlarmManager.cancel(mBatchScanIntervalIntent); return; } long batchTriggerIntervalMillis = getBatchTriggerIntervalMillis(); mAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + batchTriggerIntervalMillis, batchTriggerIntervalMillis, mBatchScanIntervalIntent); } } void stopRegularScan(ScanClient client) { void stopRegularScan(ScanClient client) { Loading @@ -306,6 +355,7 @@ public class ScanManager { removeScanFilters(client.clientIf); removeScanFilters(client.clientIf); mBatchClients.remove(client); mBatchClients.remove(client); gattClientStopBatchScanNative(client.clientIf); gattClientStopBatchScanNative(client.clientIf); setBatchAlarm(); } } void flushBatchResults(int clientIf) { void flushBatchResults(int clientIf) { Loading @@ -319,6 +369,21 @@ public class ScanManager { gattClientReadScanReportsNative(client.clientIf, resultType); gattClientReadScanReportsNative(client.clientIf, resultType); } } void cleanup() { mAlarmManager.cancel(mBatchScanIntervalIntent); } private long getBatchTriggerIntervalMillis() { long intervalMillis = Long.MAX_VALUE; for (ScanClient client : mBatchClients) { if (client.settings != null && client.settings.getReportDelayMillis() > 0) { intervalMillis = Math.min(intervalMillis, client.settings.getReportDelayMillis()); } } return intervalMillis; } // Add scan filters. The logic is: // Add scan filters. The logic is: // If no offload filter can/needs to be set, set ALLOW_ALL filter. // If no offload filter can/needs to be set, set ALLOW_ALL filter. // Otherwise offload all filters to hardware and enable all filters. // Otherwise offload all filters to hardware and enable all filters. Loading Loading @@ -430,7 +495,6 @@ public class ScanManager { break; break; case ScanFilterQueue.TYPE_MANUFACTURER_DATA: case ScanFilterQueue.TYPE_MANUFACTURER_DATA: { int len = entry.data.length; int len = entry.data.length; if (entry.data_mask.length != len) if (entry.data_mask.length != len) return; return; Loading @@ -440,7 +504,6 @@ public class ScanManager { break; break; } } } } } private void initFilterIndexStack() { private void initFilterIndexStack() { int maxFiltersSupported = int maxFiltersSupported = Loading Loading
android/app/src/com/android/bluetooth/gatt/GattService.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -43,6 +43,7 @@ import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.btservice.ProfileService; import java.util.ArrayList; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Collections; import java.util.HashMap; import java.util.HashMap; import java.util.HashSet; import java.util.HashSet; Loading Loading @@ -595,6 +596,7 @@ public class GattService extends ProfileService { if (client.filters == null || client.filters.isEmpty()) { if (client.filters == null || client.filters.isEmpty()) { return true; return true; } } if (DBG) Log.d(TAG, "result: " + scanResult.toString()); for (ScanFilter filter : client.filters) { for (ScanFilter filter : client.filters) { if (DBG) Log.d(TAG, "filter: " + filter.toString()); if (DBG) Log.d(TAG, "filter: " + filter.toString()); if (filter.matches(scanResult)) { if (filter.matches(scanResult)) { Loading Loading @@ -954,6 +956,9 @@ public class GattService extends ProfileService { ClientMap.App app = mClientMap.getById(clientIf); ClientMap.App app = mClientMap.getById(clientIf); if (app == null) return; if (app == null) return; Set<ScanResult> results = parseBatchScanResults(numRecords, reportType, recordData); Set<ScanResult> results = parseBatchScanResults(numRecords, reportType, recordData); for (ScanResult result : new ArrayList<ScanResult>(results)) { Log.d(TAG, result.getScanRecord().toString()); } app.callback.onBatchScanResults(new ArrayList<ScanResult>(results)); app.callback.onBatchScanResults(new ArrayList<ScanResult>(results)); } } Loading Loading @@ -994,6 +999,7 @@ public class GattService extends ProfileService { } } private Set<ScanResult> parseFullResults(int numRecords, byte[] batchRecord) { private Set<ScanResult> parseFullResults(int numRecords, byte[] batchRecord) { Log.d(TAG, "Batch record : " + Arrays.toString(batchRecord)); Set<ScanResult> results = new HashSet<ScanResult>(numRecords); Set<ScanResult> results = new HashSet<ScanResult>(numRecords); int position = 0; int position = 0; while (position < batchRecord.length) { while (position < batchRecord.length) { Loading @@ -1019,6 +1025,7 @@ public class GattService extends ProfileService { System.arraycopy(advertiseBytes, 0, scanRecord, 0, advertisePacketLen); System.arraycopy(advertiseBytes, 0, scanRecord, 0, advertisePacketLen); System.arraycopy(scanResponseBytes, 0, scanRecord, System.arraycopy(scanResponseBytes, 0, scanRecord, advertisePacketLen, scanResponsePacketLen); advertisePacketLen, scanResponsePacketLen); Log.d(TAG, "ScanRecord : " + Arrays.toString(scanRecord)); results.add(new ScanResult(device, ScanRecord.parseFromBytes(scanRecord), results.add(new ScanResult(device, ScanRecord.parseFromBytes(scanRecord), rssi, timestampNanos)); rssi, timestampNanos)); } } Loading
android/app/src/com/android/bluetooth/gatt/ScanFilterQueue.java +50 −3 Original line number Original line Diff line number Diff line Loading @@ -16,7 +16,10 @@ package com.android.bluetooth.gatt; package com.android.bluetooth.gatt; import android.bluetooth.BluetoothUuid; import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanFilter; import android.os.ParcelUuid; import android.util.Log; import java.util.Arrays; import java.util.Arrays; import java.util.HashSet; import java.util.HashSet; Loading @@ -32,11 +35,15 @@ import java.util.UUID; */ */ /* package */class ScanFilterQueue { /* package */class ScanFilterQueue { public static final int TYPE_DEVICE_ADDRESS = 0; public static final int TYPE_DEVICE_ADDRESS = 0; public static final int TYPE_SERVICE_DATA = 1; public static final int TYPE_SERVICE_DATA_CHANGED = 1; public static final int TYPE_SERVICE_UUID = 2; public static final int TYPE_SERVICE_UUID = 2; public static final int TYPE_SOLICIT_UUID = 3; public static final int TYPE_SOLICIT_UUID = 3; public static final int TYPE_LOCAL_NAME = 4; public static final int TYPE_LOCAL_NAME = 4; public static final int TYPE_MANUFACTURER_DATA = 5; public static final int TYPE_MANUFACTURER_DATA = 5; public static final int TYPE_SERVICE_DATA = 6; // Max length is 31 - 3(flags) - 2 (one byte for length and one byte for type). private static final int MAX_LEN_PER_FIELD = 26; // Values defined in bluedroid. // Values defined in bluedroid. private static final byte DEVICE_TYPE_ALL = 0; private static final byte DEVICE_TYPE_ALL = 0; Loading Loading @@ -91,7 +98,7 @@ import java.util.UUID; void addServiceChanged() { void addServiceChanged() { Entry entry = new Entry(); Entry entry = new Entry(); entry.type = TYPE_SERVICE_DATA; entry.type = TYPE_SERVICE_DATA_CHANGED; mEntries.add(entry); mEntries.add(entry); } } Loading Loading @@ -146,6 +153,14 @@ import java.util.UUID; mEntries.add(entry); mEntries.add(entry); } } void addServiceData(byte[] data, byte[] dataMask) { Entry entry = new Entry(); entry.type = TYPE_SERVICE_DATA; entry.data = data; entry.data_mask = dataMask; mEntries.add(entry); } Entry pop() { Entry pop() { if (isEmpty()) { if (isEmpty()) { return null; return null; Loading Loading @@ -178,7 +193,6 @@ import java.util.UUID; int getFeatureSelection() { int getFeatureSelection() { int selc = 0; int selc = 0; for (Entry entry : mEntries) { for (Entry entry : mEntries) { System.out.println("entry selc value " + (1 << entry.type)); selc |= (1 << entry.type); selc |= (1 << entry.type); } } return selc; return selc; Loading Loading @@ -212,5 +226,38 @@ import java.util.UUID; filter.getManufacturerData(), filter.getManufacturerDataMask()); filter.getManufacturerData(), filter.getManufacturerDataMask()); } } } } if (filter.getServiceDataUuid() != null && filter.getServiceData() != null) { ParcelUuid serviceDataUuid = filter.getServiceDataUuid(); byte[] serviceData = filter.getServiceData(); byte[] serviceDataMask = filter.getServiceDataMask(); if (serviceDataMask == null) { serviceDataMask = new byte[serviceData.length]; Arrays.fill(serviceDataMask, (byte) 0xFF); } serviceData = concate(serviceDataUuid, serviceData); serviceDataMask = concate(serviceDataUuid, serviceDataMask); if (serviceData != null && serviceDataMask != null) { addServiceData(serviceData, serviceDataMask); } } } private byte[] concate(ParcelUuid serviceDataUuid, byte[] serviceData) { int dataLen = 2 + (serviceData == null ? 0 : serviceData.length); // If data is too long, don't add it to hardware scan filter. if (dataLen > MAX_LEN_PER_FIELD) { return null; } byte[] concated = new byte[dataLen]; // Extract 16 bit UUID value. int uuidValue = BluetoothUuid.getServiceIdentifierFromParcelUuid( serviceDataUuid); // First two bytes are service data UUID in little-endian. concated[0] = (byte) (uuidValue & 0xFF); concated[1] = (byte) ((uuidValue >> 8) & 0xFF); if (serviceData != null) { System.arraycopy(serviceData, 0, concated, 2, serviceData.length); } return concated; } } } }
android/app/src/com/android/bluetooth/gatt/ScanManager.java +70 −7 Original line number Original line Diff line number Diff line Loading @@ -16,13 +16,20 @@ package com.android.bluetooth.gatt; package com.android.bluetooth.gatt; import android.app.AlarmManager; import android.app.PendingIntent; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter; import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanSettings; import android.bluetooth.le.ScanSettings; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; import android.os.Handler; import android.os.HandlerThread; import android.os.HandlerThread; import android.os.Looper; import android.os.Looper; import android.os.Message; import android.os.Message; import android.os.SystemClock; import android.util.Log; import android.util.Log; import com.android.bluetooth.Utils; import com.android.bluetooth.Utils; Loading Loading @@ -57,6 +64,9 @@ public class ScanManager { private static final int MSG_STOP_BLE_SCAN = 1; private static final int MSG_STOP_BLE_SCAN = 1; private static final int MSG_FLUSH_BATCH_RESULTS = 2; private static final int MSG_FLUSH_BATCH_RESULTS = 2; private static final String ACTION_REFRESH_BATCHED_SCAN = "com.android.bluetooth.gatt.REFRESH_BATCHED_SCAN"; // Timeout for each controller operation. // Timeout for each controller operation. private static final int OPERATION_TIME_OUT_MILLIS = 500; private static final int OPERATION_TIME_OUT_MILLIS = 500; Loading @@ -72,8 +82,8 @@ public class ScanManager { ScanManager(GattService service) { ScanManager(GattService service) { mRegularScanClients = new HashSet<ScanClient>(); mRegularScanClients = new HashSet<ScanClient>(); mBatchClients = new HashSet<ScanClient>(); mBatchClients = new HashSet<ScanClient>(); mScanNative = new ScanNative(); mService = service; mService = service; mScanNative = new ScanNative(); } } void start() { void start() { Loading @@ -85,6 +95,7 @@ public class ScanManager { void cleanup() { void cleanup() { mRegularScanClients.clear(); mRegularScanClients.clear(); mBatchClients.clear(); mBatchClients.clear(); mScanNative.cleanup(); } } /** /** Loading Loading @@ -236,10 +247,34 @@ public class ScanManager { private final Deque<Integer> mFilterIndexStack; private final Deque<Integer> mFilterIndexStack; // Map of clientIf and Filter indices used by client. // Map of clientIf and Filter indices used by client. private final Map<Integer, Deque<Integer>> mClientFilterIndexMap; private final Map<Integer, Deque<Integer>> mClientFilterIndexMap; private AlarmManager mAlarmManager; private PendingIntent mBatchScanIntervalIntent; ScanNative() { ScanNative() { mFilterIndexStack = new ArrayDeque<Integer>(); mFilterIndexStack = new ArrayDeque<Integer>(); mClientFilterIndexMap = new HashMap<Integer, Deque<Integer>>(); mClientFilterIndexMap = new HashMap<Integer, Deque<Integer>>(); mAlarmManager = (AlarmManager) mService.getSystemService(Context.ALARM_SERVICE); Intent batchIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null); mBatchScanIntervalIntent = PendingIntent.getBroadcast(mService, 0, batchIntent, 0); IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_REFRESH_BATCHED_SCAN); mService.registerReceiver( new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.d(TAG, "awakened up at time " + SystemClock.elapsedRealtime()); String action = intent.getAction(); if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) { if (mBatchClients.isEmpty()) { return; } // TODO: find out if we need to flush all clients at once. flushBatchScanResults(mBatchClients.iterator().next()); } } }, filter); } } private void resetCountDownLatch() { private void resetCountDownLatch() { Loading Loading @@ -286,10 +321,24 @@ public class ScanManager { int scanWindowUnit = 8; int scanWindowUnit = 8; int discardRule = 2; int discardRule = 2; int addressType = 0; int addressType = 0; logd("Starting BLE batch scan"); gattClientStartBatchScanNative(client.clientIf, scanMode, scanIntervalUnit, gattClientStartBatchScanNative(client.clientIf, scanMode, scanIntervalUnit, scanWindowUnit, scanWindowUnit, addressType, discardRule); addressType, logd("Starting BLE batch scan, scanMode -" + scanMode); discardRule); gattClientStartBatchScanNative(client.clientIf, scanMode, scanIntervalUnit, scanWindowUnit, addressType, discardRule); setBatchAlarm(); } private void setBatchAlarm() { if (mBatchClients.isEmpty()) { mAlarmManager.cancel(mBatchScanIntervalIntent); return; } long batchTriggerIntervalMillis = getBatchTriggerIntervalMillis(); mAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + batchTriggerIntervalMillis, batchTriggerIntervalMillis, mBatchScanIntervalIntent); } } void stopRegularScan(ScanClient client) { void stopRegularScan(ScanClient client) { Loading @@ -306,6 +355,7 @@ public class ScanManager { removeScanFilters(client.clientIf); removeScanFilters(client.clientIf); mBatchClients.remove(client); mBatchClients.remove(client); gattClientStopBatchScanNative(client.clientIf); gattClientStopBatchScanNative(client.clientIf); setBatchAlarm(); } } void flushBatchResults(int clientIf) { void flushBatchResults(int clientIf) { Loading @@ -319,6 +369,21 @@ public class ScanManager { gattClientReadScanReportsNative(client.clientIf, resultType); gattClientReadScanReportsNative(client.clientIf, resultType); } } void cleanup() { mAlarmManager.cancel(mBatchScanIntervalIntent); } private long getBatchTriggerIntervalMillis() { long intervalMillis = Long.MAX_VALUE; for (ScanClient client : mBatchClients) { if (client.settings != null && client.settings.getReportDelayMillis() > 0) { intervalMillis = Math.min(intervalMillis, client.settings.getReportDelayMillis()); } } return intervalMillis; } // Add scan filters. The logic is: // Add scan filters. The logic is: // If no offload filter can/needs to be set, set ALLOW_ALL filter. // If no offload filter can/needs to be set, set ALLOW_ALL filter. // Otherwise offload all filters to hardware and enable all filters. // Otherwise offload all filters to hardware and enable all filters. Loading Loading @@ -430,7 +495,6 @@ public class ScanManager { break; break; case ScanFilterQueue.TYPE_MANUFACTURER_DATA: case ScanFilterQueue.TYPE_MANUFACTURER_DATA: { int len = entry.data.length; int len = entry.data.length; if (entry.data_mask.length != len) if (entry.data_mask.length != len) return; return; Loading @@ -440,7 +504,6 @@ public class ScanManager { break; break; } } } } } private void initFilterIndexStack() { private void initFilterIndexStack() { int maxFiltersSupported = int maxFiltersSupported = Loading