ScanManager.java revision e34b91565499994a4b04a1014432c8f90678972a
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 com.android.bluetooth.gatt; 18 19import android.app.AlarmManager; 20import android.app.PendingIntent; 21import android.bluetooth.BluetoothAdapter; 22import android.bluetooth.le.ScanFilter; 23import android.bluetooth.le.ScanSettings; 24import android.content.BroadcastReceiver; 25import android.content.Context; 26import android.content.Intent; 27import android.content.IntentFilter; 28import android.os.Handler; 29import android.os.HandlerThread; 30import android.os.Looper; 31import android.os.Message; 32import android.os.SystemClock; 33import android.util.Log; 34 35import com.android.bluetooth.Utils; 36import com.android.bluetooth.btservice.AdapterService; 37 38import java.util.ArrayDeque; 39import java.util.ArrayList; 40import java.util.Deque; 41import java.util.HashMap; 42import java.util.HashSet; 43import java.util.List; 44import java.util.Map; 45import java.util.Set; 46import java.util.concurrent.CountDownLatch; 47import java.util.concurrent.TimeUnit; 48 49/** 50 * Class that handles Bluetooth LE scan related operations. 51 * 52 * @hide 53 */ 54public class ScanManager { 55 private static final boolean DBG = GattServiceConfig.DBG; 56 private static final String TAG = GattServiceConfig.TAG_PREFIX + "ScanManager"; 57 58 // Result type defined in bt stack. Need to be accessed by GattService. 59 static final int SCAN_RESULT_TYPE_TRUNCATED = 1; 60 static final int SCAN_RESULT_TYPE_FULL = 2; 61 62 // Internal messages for handling BLE scan operations. 63 private static final int MSG_START_BLE_SCAN = 0; 64 private static final int MSG_STOP_BLE_SCAN = 1; 65 private static final int MSG_FLUSH_BATCH_RESULTS = 2; 66 67 private static final String ACTION_REFRESH_BATCHED_SCAN = 68 "com.android.bluetooth.gatt.REFRESH_BATCHED_SCAN"; 69 70 // Timeout for each controller operation. 71 private static final int OPERATION_TIME_OUT_MILLIS = 500; 72 73 private static int lastConfiguredScanSetting = Integer.MIN_VALUE; 74 75 private GattService mService; 76 private ScanNative mScanNative; 77 private ClientHandler mHandler; 78 79 private Set<ScanClient> mRegularScanClients; 80 private Set<ScanClient> mBatchClients; 81 82 private CountDownLatch mLatch; 83 84 ScanManager(GattService service) { 85 mRegularScanClients = new HashSet<ScanClient>(); 86 mBatchClients = new HashSet<ScanClient>(); 87 mService = service; 88 mScanNative = new ScanNative(); 89 } 90 91 void start() { 92 HandlerThread thread = new HandlerThread("BluetoothScanManager"); 93 thread.start(); 94 mHandler = new ClientHandler(thread.getLooper()); 95 } 96 97 void cleanup() { 98 mRegularScanClients.clear(); 99 mBatchClients.clear(); 100 mScanNative.cleanup(); 101 } 102 103 /** 104 * Returns the combined scan queue of regular scans and batch scans. 105 */ 106 List<ScanClient> scanQueue() { 107 List<ScanClient> clients = new ArrayList<>(); 108 clients.addAll(mRegularScanClients); 109 clients.addAll(mBatchClients); 110 return clients; 111 } 112 113 void startScan(ScanClient client) { 114 sendMessage(MSG_START_BLE_SCAN, client); 115 } 116 117 void stopScan(ScanClient client) { 118 sendMessage(MSG_STOP_BLE_SCAN, client); 119 } 120 121 void flushBatchScanResults(ScanClient client) { 122 sendMessage(MSG_FLUSH_BATCH_RESULTS, client); 123 } 124 125 void callbackDone(int clientIf, int status) { 126 logd("callback done for clientIf - " + clientIf + " status - " + status); 127 if (status == 0) { 128 mLatch.countDown(); 129 } 130 // TODO: add a callback for scan failure. 131 } 132 133 private void sendMessage(int what, ScanClient client) { 134 Message message = new Message(); 135 message.what = what; 136 message.obj = client; 137 mHandler.sendMessage(message); 138 } 139 140 private boolean isFilteringSupported() { 141 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 142 return adapter.isOffloadedFilteringSupported(); 143 } 144 145 // Handler class that handles BLE scan operations. 146 private class ClientHandler extends Handler { 147 148 ClientHandler(Looper looper) { 149 super(looper); 150 } 151 152 @Override 153 public void handleMessage(Message msg) { 154 ScanClient client = (ScanClient) msg.obj; 155 switch (msg.what) { 156 case MSG_START_BLE_SCAN: 157 handleStartScan(client); 158 break; 159 case MSG_STOP_BLE_SCAN: 160 handleStopScan(client); 161 break; 162 case MSG_FLUSH_BATCH_RESULTS: 163 handleFlushBatchResults(client); 164 break; 165 default: 166 // Shouldn't happen. 167 Log.e(TAG, "received an unkown message : " + msg.what); 168 } 169 } 170 171 void handleStartScan(ScanClient client) { 172 Utils.enforceAdminPermission(mService); 173 logd("handling starting scan"); 174 175 if (!isScanSupported(client)) { 176 Log.e(TAG, "Scan settings not supported"); 177 return; 178 } 179 180 if (mRegularScanClients.contains(client) || mBatchClients.contains(client)) { 181 Log.e(TAG, "Scan already started"); 182 return; 183 } 184 // Begin scan operations. 185 if (isBatchClient(client)) { 186 mBatchClients.add(client); 187 mScanNative.startBatchScan(client); 188 } else { 189 mRegularScanClients.add(client); 190 mScanNative.startRegularScan(client); 191 mScanNative.configureRegularScanParams(); 192 } 193 } 194 195 void handleStopScan(ScanClient client) { 196 Utils.enforceAdminPermission(mService); 197 if (mRegularScanClients.contains(client)) { 198 mRegularScanClients.remove(client); 199 mScanNative.configureRegularScanParams(); 200 mScanNative.stopRegularScan(client); 201 } else { 202 mBatchClients.remove(client); 203 mScanNative.stopBatchScan(client); 204 } 205 } 206 207 void handleFlushBatchResults(ScanClient client) { 208 Utils.enforceAdminPermission(mService); 209 if (!mBatchClients.contains(client)) { 210 return; 211 } 212 mScanNative.flushBatchResults(client.clientIf); 213 } 214 215 private boolean isBatchClient(ScanClient client) { 216 if (client == null || client.settings == null) { 217 return false; 218 } 219 ScanSettings settings = client.settings; 220 return settings.getCallbackType() == ScanSettings.CALLBACK_TYPE_ALL_MATCHES && 221 settings.getReportDelayMillis() != 0; 222 } 223 224 private boolean isScanSupported(ScanClient client) { 225 if (client == null || client.settings == null) { 226 return true; 227 } 228 ScanSettings settings = client.settings; 229 if (isFilteringSupported()) { 230 return true; 231 } 232 return settings.getCallbackType() == ScanSettings.CALLBACK_TYPE_ALL_MATCHES && 233 settings.getReportDelayMillis() == 0; 234 } 235 } 236 237 private class ScanNative { 238 239 // Delivery mode defined in bt stack. 240 private static final int DELIVERY_MODE_IMMEDIATE = 0; 241 private static final int DELIVERY_MODE_ON_FOUND = 1; 242 private static final int DELIVERY_MODE_BATCH = 2; 243 244 private static final int ALLOW_ALL_FILTER_INDEX = 1; 245 private static final int ALLOW_ALL_FILTER_SELECTION = 0; 246 247 /** 248 * Scan params corresponding to scan setting 249 */ 250 private static final int SCAN_MODE_LOW_POWER_WINDOW_MS = 500; 251 private static final int SCAN_MODE_LOW_POWER_INTERVAL_MS = 5000; 252 private static final int SCAN_MODE_BALANCED_WINDOW_MS = 2000; 253 private static final int SCAN_MODE_BALANCED_INTERVAL_MS = 5000; 254 private static final int SCAN_MODE_LOW_LATENCY_WINDOW_MS = 5000; 255 private static final int SCAN_MODE_LOW_LATENCY_INTERVAL_MS = 5000; 256 257 258 // The logic is AND for each filter field. 259 private static final int LIST_LOGIC_TYPE = 0x1111111; 260 private static final int FILTER_LOGIC_TYPE = 1; 261 // Filter indices that are available to user. It's sad we need to maintain filter index. 262 private final Deque<Integer> mFilterIndexStack; 263 // Map of clientIf and Filter indices used by client. 264 private final Map<Integer, Deque<Integer>> mClientFilterIndexMap; 265 private AlarmManager mAlarmManager; 266 private PendingIntent mBatchScanIntervalIntent; 267 268 ScanNative() { 269 mFilterIndexStack = new ArrayDeque<Integer>(); 270 mClientFilterIndexMap = new HashMap<Integer, Deque<Integer>>(); 271 272 mAlarmManager = (AlarmManager) mService.getSystemService(Context.ALARM_SERVICE); 273 Intent batchIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null); 274 mBatchScanIntervalIntent = PendingIntent.getBroadcast(mService, 0, batchIntent, 0); 275 IntentFilter filter = new IntentFilter(); 276 filter.addAction(ACTION_REFRESH_BATCHED_SCAN); 277 mService.registerReceiver( 278 new BroadcastReceiver() { 279 @Override 280 public void onReceive(Context context, Intent intent) { 281 Log.d(TAG, "awakened up at time " + SystemClock.elapsedRealtime()); 282 String action = intent.getAction(); 283 284 if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) { 285 if (mBatchClients.isEmpty()) { 286 return; 287 } 288 // TODO: find out if we need to flush all clients at once. 289 flushBatchScanResults(mBatchClients.iterator().next()); 290 } 291 } 292 }, filter); 293 } 294 295 private void resetCountDownLatch() { 296 mLatch = new CountDownLatch(1); 297 } 298 299 // Returns true if mLatch reaches 0, false if timeout or interrupted. 300 private boolean waitForCallback() { 301 try { 302 return mLatch.await(OPERATION_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); 303 } catch (InterruptedException e) { 304 return false; 305 } 306 } 307 308 void configureRegularScanParams() { 309 if (DBG) Log.d(TAG, "configureRegularScanParams() - queue=" + mRegularScanClients.size()); 310 int curScanSetting = Integer.MIN_VALUE; 311 312 for(ScanClient client : mRegularScanClients) { 313 // ScanClient scan settings are assumed to be monotonically increasing in value for more 314 // power hungry(higher duty cycle) operation 315 if (client.settings.getScanMode() > curScanSetting) { 316 curScanSetting = client.settings.getScanMode(); 317 } 318 } 319 320 if (DBG) Log.d(TAG, "configureRegularScanParams() - ScanSetting Scan mode=" + curScanSetting + 321 " lastConfiguredScanSetting=" + lastConfiguredScanSetting); 322 323 if (curScanSetting != Integer.MIN_VALUE) { 324 if (curScanSetting != lastConfiguredScanSetting) { 325 int scanWindow, scanInterval; 326 switch (curScanSetting){ 327 case ScanSettings.SCAN_MODE_LOW_POWER: 328 scanWindow = SCAN_MODE_LOW_POWER_WINDOW_MS; 329 scanInterval = SCAN_MODE_LOW_POWER_INTERVAL_MS; 330 break; 331 case ScanSettings.SCAN_MODE_BALANCED: 332 scanWindow = SCAN_MODE_BALANCED_WINDOW_MS; 333 scanInterval = SCAN_MODE_BALANCED_INTERVAL_MS; 334 break; 335 case ScanSettings.SCAN_MODE_LOW_LATENCY: 336 scanWindow = SCAN_MODE_LOW_LATENCY_WINDOW_MS; 337 scanInterval = SCAN_MODE_LOW_LATENCY_INTERVAL_MS; 338 break; 339 default: 340 Log.e(TAG, "Invalid value for curScanSetting " + curScanSetting); 341 scanWindow = SCAN_MODE_LOW_POWER_WINDOW_MS; 342 scanInterval = SCAN_MODE_LOW_POWER_INTERVAL_MS; 343 break; 344 } 345 // convert scanWindow and scanInterval from ms to LE scan units(0.625ms) 346 scanWindow = (scanWindow * 1000)/625; 347 scanInterval = (scanInterval * 1000)/625; 348 gattClientScanNative(false); 349 gattSetScanParametersNative(scanInterval, scanWindow); 350 gattClientScanNative(true); 351 lastConfiguredScanSetting = curScanSetting; 352 } 353 } else { 354 lastConfiguredScanSetting = curScanSetting; 355 if (DBG) Log.d(TAG, "configureRegularScanParams() - queue emtpy, scan stopped"); 356 } 357 } 358 359 360 void startRegularScan(ScanClient client) { 361 if (mFilterIndexStack.isEmpty() && isFilteringSupported()) { 362 initFilterIndexStack(); 363 } 364 if (isFilteringSupported()) { 365 configureScanFilters(client); 366 } 367 // Start scan native only for the first client. 368 if (mRegularScanClients.size() == 1) { 369 gattClientScanNative(true); 370 } 371 } 372 373 void startBatchScan(ScanClient client) { 374 if (mFilterIndexStack.isEmpty() && isFilteringSupported()) { 375 initFilterIndexStack(); 376 } 377 configureScanFilters(client); 378 int fullScanPercent = 50; 379 int notifyThreshold = 95; 380 resetCountDownLatch(); 381 logd("configuring batch scan storage, appIf " + client.clientIf); 382 gattClientConfigBatchScanStorageNative(client.clientIf, fullScanPercent, 383 100 - fullScanPercent, notifyThreshold); 384 waitForCallback(); 385 int scanMode = getResultType(client.settings); 386 // TODO: configure scan parameters. 387 int scanIntervalUnit = 8; 388 int scanWindowUnit = 8; 389 int discardRule = 2; 390 int addressType = 0; 391 logd("Starting BLE batch scan, scanMode -" + scanMode); 392 gattClientStartBatchScanNative(client.clientIf, scanMode, scanIntervalUnit, 393 scanWindowUnit, addressType, discardRule); 394 setBatchAlarm(); 395 } 396 397 private void setBatchAlarm() { 398 if (mBatchClients.isEmpty()) { 399 mAlarmManager.cancel(mBatchScanIntervalIntent); 400 return; 401 } 402 long batchTriggerIntervalMillis = getBatchTriggerIntervalMillis(); 403 mAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 404 SystemClock.elapsedRealtime() + batchTriggerIntervalMillis, 405 batchTriggerIntervalMillis, 406 mBatchScanIntervalIntent); 407 } 408 409 void stopRegularScan(ScanClient client) { 410 // Remove scan filters and recycle filter indices. 411 removeScanFilters(client.clientIf); 412 mRegularScanClients.remove(client); 413 if (mRegularScanClients.isEmpty()) { 414 logd("stop scan"); 415 gattClientScanNative(false); 416 } 417 } 418 419 void stopBatchScan(ScanClient client) { 420 removeScanFilters(client.clientIf); 421 mBatchClients.remove(client); 422 gattClientStopBatchScanNative(client.clientIf); 423 setBatchAlarm(); 424 } 425 426 void flushBatchResults(int clientIf) { 427 logd("flushPendingBatchResults - clientIf = " + clientIf); 428 ScanClient client = getBatchScanClient(clientIf); 429 if (client == null) { 430 logd("unknown client : " + clientIf); 431 return; 432 } 433 int resultType = getResultType(client.settings); 434 gattClientReadScanReportsNative(client.clientIf, resultType); 435 } 436 437 void cleanup() { 438 mAlarmManager.cancel(mBatchScanIntervalIntent); 439 } 440 441 private long getBatchTriggerIntervalMillis() { 442 long intervalMillis = Long.MAX_VALUE; 443 for (ScanClient client : mBatchClients) { 444 if (client.settings != null && client.settings.getReportDelayMillis() > 0) { 445 intervalMillis = Math.min(intervalMillis, 446 client.settings.getReportDelayMillis()); 447 } 448 } 449 return intervalMillis; 450 } 451 452 // Add scan filters. The logic is: 453 // If no offload filter can/needs to be set, set ALLOW_ALL filter. 454 // Otherwise offload all filters to hardware and enable all filters. 455 private void configureScanFilters(ScanClient client) { 456 int clientIf = client.clientIf; 457 resetCountDownLatch(); 458 gattClientScanFilterEnableNative(clientIf, true); 459 waitForCallback(); 460 461 if (shouldUseAllowAllFilter(client)) { 462 resetCountDownLatch(); 463 configureFilterParamter(clientIf, client, ALLOW_ALL_FILTER_SELECTION, 464 ALLOW_ALL_FILTER_INDEX); 465 waitForCallback(); 466 } else { 467 Deque<Integer> clientFilterIndices = new ArrayDeque<Integer>(); 468 for (ScanFilter filter : client.filters) { 469 ScanFilterQueue queue = new ScanFilterQueue(); 470 queue.addScanFilter(filter); 471 int featureSelection = queue.getFeatureSelection(); 472 int filterIndex = mFilterIndexStack.pop(); 473 while (!queue.isEmpty()) { 474 resetCountDownLatch(); 475 addFilterToController(clientIf, queue.pop(), filterIndex); 476 waitForCallback(); 477 } 478 resetCountDownLatch(); 479 configureFilterParamter(clientIf, client, featureSelection, filterIndex); 480 waitForCallback(); 481 clientFilterIndices.add(filterIndex); 482 } 483 mClientFilterIndexMap.put(clientIf, clientFilterIndices); 484 } 485 } 486 487 private void removeScanFilters(int clientIf) { 488 logd("removeScanFilters, clientIf - " + clientIf); 489 Deque<Integer> filterIndices = mClientFilterIndexMap.remove(clientIf); 490 if (filterIndices != null) { 491 mFilterIndexStack.addAll(filterIndices); 492 for (Integer filterIndex : filterIndices) { 493 resetCountDownLatch(); 494 gattClientScanFilterParamDeleteNative(clientIf, filterIndex); 495 waitForCallback(); 496 } 497 } 498 } 499 500 private ScanClient getBatchScanClient(int clientIf) { 501 for (ScanClient client : mBatchClients) { 502 if (client.clientIf == clientIf) { 503 return client; 504 } 505 } 506 return null; 507 } 508 509 /** 510 * Return batch scan result type value defined in bt stack. 511 */ 512 private int getResultType(ScanSettings settings) { 513 return settings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_FULL ? 514 SCAN_RESULT_TYPE_FULL : SCAN_RESULT_TYPE_TRUNCATED; 515 } 516 517 // Check if ALLOW_FILTER should be used for the client. 518 private boolean shouldUseAllowAllFilter(ScanClient client) { 519 if (client == null) { 520 return true; 521 } 522 if (client.filters == null || client.filters.isEmpty()) { 523 return true; 524 } 525 return client.filters.size() < mClientFilterIndexMap.size(); 526 } 527 528 private void addFilterToController(int clientIf, ScanFilterQueue.Entry entry, 529 int filterIndex) { 530 logd("addFilterToController: " + entry.type); 531 switch (entry.type) { 532 case ScanFilterQueue.TYPE_DEVICE_ADDRESS: 533 logd("add address " + entry.address); 534 gattClientScanFilterAddNative(clientIf, entry.type, filterIndex, 0, 0, 0, 0, 0, 535 0, 536 "", entry.address, (byte) 0, new byte[0], new byte[0]); 537 break; 538 539 case ScanFilterQueue.TYPE_SERVICE_DATA: 540 gattClientScanFilterAddNative(clientIf, entry.type, filterIndex, 0, 0, 0, 0, 0, 541 0, 542 "", "", (byte) 0, entry.data, entry.data_mask); 543 break; 544 545 case ScanFilterQueue.TYPE_SERVICE_UUID: 546 case ScanFilterQueue.TYPE_SOLICIT_UUID: 547 gattClientScanFilterAddNative(clientIf, entry.type, filterIndex, 0, 0, 548 entry.uuid.getLeastSignificantBits(), 549 entry.uuid.getMostSignificantBits(), 550 entry.uuid_mask.getLeastSignificantBits(), 551 entry.uuid_mask.getMostSignificantBits(), 552 "", "", (byte) 0, new byte[0], new byte[0]); 553 break; 554 555 case ScanFilterQueue.TYPE_LOCAL_NAME: 556 logd("adding filters: " + entry.name); 557 gattClientScanFilterAddNative(clientIf, entry.type, filterIndex, 0, 0, 0, 0, 0, 558 0, 559 entry.name, "", (byte) 0, new byte[0], new byte[0]); 560 break; 561 562 case ScanFilterQueue.TYPE_MANUFACTURER_DATA: 563 int len = entry.data.length; 564 if (entry.data_mask.length != len) 565 return; 566 gattClientScanFilterAddNative(clientIf, entry.type, filterIndex, entry.company, 567 entry.company_mask, 0, 0, 0, 0, "", "", (byte) 0, 568 entry.data, entry.data_mask); 569 break; 570 } 571 } 572 573 private void initFilterIndexStack() { 574 int maxFiltersSupported = 575 AdapterService.getAdapterService().getNumOfOffloadedScanFilterSupported(); 576 // Start from index 2 as index 0 is reserved for ALLOW_ALL filter in Settings app and 577 // index 1 is reserved for ALLOW_ALL filter for regular apps. 578 for (int i = 2; i < maxFiltersSupported; ++i) { 579 mFilterIndexStack.add(i); 580 } 581 } 582 583 // Configure filter parameters. 584 private void configureFilterParamter(int clientIf, ScanClient client, int featureSelection, 585 int filterIndex) { 586 int deliveryMode = getDeliveryMode(client); 587 int rssiThreshold = Byte.MIN_VALUE; 588 gattClientScanFilterParamAddNative( 589 clientIf, filterIndex, featureSelection, LIST_LOGIC_TYPE, 590 FILTER_LOGIC_TYPE, rssiThreshold, rssiThreshold, deliveryMode, 591 0, 0, 0); 592 } 593 594 // Get delivery mode based on scan settings. 595 private int getDeliveryMode(ScanClient client) { 596 if (client == null) { 597 return DELIVERY_MODE_IMMEDIATE; 598 } 599 ScanSettings settings = client.settings; 600 if (settings == null) { 601 return DELIVERY_MODE_IMMEDIATE; 602 } 603 // TODO: double check whether it makes sense to use the same delivery mode for found and 604 // lost. 605 if ((settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0 606 || (settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_MATCH_LOST) != 0) { 607 return DELIVERY_MODE_ON_FOUND; 608 } 609 return settings.getReportDelayMillis() == 0 ? DELIVERY_MODE_IMMEDIATE 610 : DELIVERY_MODE_BATCH; 611 } 612 613 /************************** Regular scan related native methods **************************/ 614 private native void gattClientScanNative(boolean start); 615 616 private native void gattSetScanParametersNative(int scan_interval, 617 int scan_window); 618 619 /************************** Filter related native methods ********************************/ 620 private native void gattClientScanFilterAddNative(int client_if, 621 int filter_type, int filter_index, int company_id, 622 int company_id_mask, long uuid_lsb, long uuid_msb, 623 long uuid_mask_lsb, long uuid_mask_msb, String name, 624 String address, byte addr_type, byte[] data, byte[] mask); 625 626 private native void gattClientScanFilterDeleteNative(int client_if, 627 int filter_type, int filter_index, int company_id, 628 int company_id_mask, long uuid_lsb, long uuid_msb, 629 long uuid_mask_lsb, long uuid_mask_msb, String name, 630 String address, byte addr_type, byte[] data, byte[] mask); 631 632 private native void gattClientScanFilterParamAddNative( 633 int client_if, int filt_index, int feat_seln, 634 int list_logic_type, int filt_logic_type, int rssi_high_thres, 635 int rssi_low_thres, int dely_mode, int found_timeout, 636 int lost_timeout, int found_timeout_cnt); 637 638 // Note this effectively remove scan filters for ALL clients. 639 private native void gattClientScanFilterParamClearAllNative( 640 int client_if); 641 642 private native void gattClientScanFilterParamDeleteNative( 643 int client_if, int filt_index); 644 645 private native void gattClientScanFilterClearNative(int client_if, 646 int filter_index); 647 648 private native void gattClientScanFilterEnableNative(int client_if, 649 boolean enable); 650 651 /************************** Batch related native methods *********************************/ 652 private native void gattClientConfigBatchScanStorageNative(int client_if, 653 int max_full_reports_percent, int max_truncated_reports_percent, 654 int notify_threshold_percent); 655 656 private native void gattClientStartBatchScanNative(int client_if, int scan_mode, 657 int scan_interval_unit, int scan_window_unit, int address_type, int discard_rule); 658 659 private native void gattClientStopBatchScanNative(int client_if); 660 661 private native void gattClientReadScanReportsNative(int client_if, int scan_type); 662 } 663 664 private void logd(String s) { 665 Log.d(TAG, s); 666 } 667} 668