• 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 com.android.bluetooth.gatt;
18 
19 import android.app.AlarmManager;
20 import android.app.PendingIntent;
21 import android.bluetooth.BluetoothAdapter;
22 import android.bluetooth.le.ScanCallback;
23 import android.bluetooth.le.ScanFilter;
24 import android.bluetooth.le.ScanSettings;
25 import android.content.BroadcastReceiver;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.os.Handler;
30 import android.os.HandlerThread;
31 import android.os.Looper;
32 import android.os.Message;
33 import android.os.RemoteException;
34 import android.os.ServiceManager;
35 import android.os.SystemClock;
36 import android.util.Log;
37 
38 import com.android.bluetooth.Utils;
39 import com.android.bluetooth.btservice.AdapterService;
40 import com.android.internal.app.IBatteryStats;
41 
42 import java.util.ArrayDeque;
43 import java.util.Collections;
44 import java.util.Deque;
45 import java.util.HashMap;
46 import java.util.HashSet;
47 import java.util.Map;
48 import java.util.Set;
49 import java.util.concurrent.ConcurrentHashMap;
50 import java.util.concurrent.CountDownLatch;
51 import java.util.concurrent.TimeUnit;
52 
53 /**
54  * Class that handles Bluetooth LE scan related operations.
55  *
56  * @hide
57  */
58 public class ScanManager {
59     private static final boolean DBG = GattServiceConfig.DBG;
60     private static final String TAG = GattServiceConfig.TAG_PREFIX + "ScanManager";
61 
62     // Result type defined in bt stack. Need to be accessed by GattService.
63     static final int SCAN_RESULT_TYPE_TRUNCATED = 1;
64     static final int SCAN_RESULT_TYPE_FULL = 2;
65     static final int SCAN_RESULT_TYPE_BOTH = 3;
66 
67     // Internal messages for handling BLE scan operations.
68     private static final int MSG_START_BLE_SCAN = 0;
69     private static final int MSG_STOP_BLE_SCAN = 1;
70     private static final int MSG_FLUSH_BATCH_RESULTS = 2;
71     private static final int MSG_SCAN_TIMEOUT = 3;
72 
73     private static final String ACTION_REFRESH_BATCHED_SCAN =
74             "com.android.bluetooth.gatt.REFRESH_BATCHED_SCAN";
75 
76     // Timeout for each controller operation.
77     private static final int OPERATION_TIME_OUT_MILLIS = 500;
78 
79     private int mLastConfiguredScanSetting = Integer.MIN_VALUE;
80     // Scan parameters for batch scan.
81     private BatchScanParams mBatchScanParms;
82 
83     private Integer curUsedTrackableAdvertisements;
84     private GattService mService;
85     private IBatteryStats mBatteryStats;
86     private BroadcastReceiver mBatchAlarmReceiver;
87     private boolean mBatchAlarmReceiverRegistered;
88     private ScanNative mScanNative;
89     private ClientHandler mHandler;
90 
91     private Set<ScanClient> mRegularScanClients;
92     private Set<ScanClient> mBatchClients;
93 
94     private CountDownLatch mLatch;
95 
ScanManager(GattService service)96     ScanManager(GattService service) {
97         mRegularScanClients = Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
98         mBatchClients = Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
99         mService = service;
100         mScanNative = new ScanNative();
101         curUsedTrackableAdvertisements = 0;
102     }
103 
start()104     void start() {
105         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batterystats"));
106         HandlerThread thread = new HandlerThread("BluetoothScanManager");
107         thread.start();
108         mHandler = new ClientHandler(thread.getLooper());
109     }
110 
cleanup()111     void cleanup() {
112         mRegularScanClients.clear();
113         mBatchClients.clear();
114         mScanNative.cleanup();
115     }
116 
117     /**
118      * Returns the regular scan queue.
119      */
getRegularScanQueue()120     Set<ScanClient> getRegularScanQueue() {
121         return mRegularScanClients;
122     }
123 
124     /**
125      * Returns batch scan queue.
126      */
getBatchScanQueue()127     Set<ScanClient> getBatchScanQueue() {
128         return mBatchClients;
129     }
130 
131     /**
132      * Returns a set of full batch scan clients.
133      */
getFullBatchScanQueue()134     Set<ScanClient> getFullBatchScanQueue() {
135         // TODO: split full batch scan clients and truncated batch clients so we don't need to
136         // construct this every time.
137         Set<ScanClient> fullBatchClients = new HashSet<ScanClient>();
138         for (ScanClient client : mBatchClients) {
139             if (client.settings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_FULL) {
140                 fullBatchClients.add(client);
141             }
142         }
143         return fullBatchClients;
144     }
145 
startScan(ScanClient client)146     void startScan(ScanClient client) {
147         sendMessage(MSG_START_BLE_SCAN, client);
148     }
149 
stopScan(ScanClient client)150     void stopScan(ScanClient client) {
151         sendMessage(MSG_STOP_BLE_SCAN, client);
152     }
153 
flushBatchScanResults(ScanClient client)154     void flushBatchScanResults(ScanClient client) {
155         sendMessage(MSG_FLUSH_BATCH_RESULTS, client);
156     }
157 
callbackDone(int clientIf, int status)158     void callbackDone(int clientIf, int status) {
159         logd("callback done for clientIf - " + clientIf + " status - " + status);
160         if (status == 0) {
161             mLatch.countDown();
162         }
163         // TODO: add a callback for scan failure.
164     }
165 
sendMessage(int what, ScanClient client)166     private void sendMessage(int what, ScanClient client) {
167         Message message = new Message();
168         message.what = what;
169         message.obj = client;
170         mHandler.sendMessage(message);
171     }
172 
isFilteringSupported()173     private boolean isFilteringSupported() {
174         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
175         return adapter.isOffloadedFilteringSupported();
176     }
177 
178     // Handler class that handles BLE scan operations.
179     private class ClientHandler extends Handler {
180 
ClientHandler(Looper looper)181         ClientHandler(Looper looper) {
182             super(looper);
183         }
184 
185         @Override
handleMessage(Message msg)186         public void handleMessage(Message msg) {
187             ScanClient client = (ScanClient) msg.obj;
188             switch (msg.what) {
189                 case MSG_START_BLE_SCAN:
190                     handleStartScan(client);
191                     break;
192                 case MSG_STOP_BLE_SCAN:
193                     handleStopScan(client);
194                     break;
195                 case MSG_FLUSH_BATCH_RESULTS:
196                     handleFlushBatchResults(client);
197                     break;
198                 case MSG_SCAN_TIMEOUT:
199                     mScanNative.regularScanTimeout(client);
200                     break;
201                 default:
202                     // Shouldn't happen.
203                     Log.e(TAG, "received an unkown message : " + msg.what);
204             }
205         }
206 
handleStartScan(ScanClient client)207         void handleStartScan(ScanClient client) {
208             Utils.enforceAdminPermission(mService);
209             logd("handling starting scan");
210 
211             if (!isScanSupported(client)) {
212                 Log.e(TAG, "Scan settings not supported");
213                 return;
214             }
215 
216             if (mRegularScanClients.contains(client) || mBatchClients.contains(client)) {
217                 Log.e(TAG, "Scan already started");
218                 return;
219             }
220             // Begin scan operations.
221             if (isBatchClient(client)) {
222                 mBatchClients.add(client);
223                 mScanNative.startBatchScan(client);
224             } else {
225                 mRegularScanClients.add(client);
226                 mScanNative.startRegularScan(client);
227                 if (!mScanNative.isOpportunisticScanClient(client)) {
228                     mScanNative.configureRegularScanParams();
229 
230                     if (!mScanNative.isExemptFromScanDowngrade(client)) {
231                         Message msg = mHandler.obtainMessage(MSG_SCAN_TIMEOUT);
232                         msg.obj = client;
233                         // Only one timeout message should exist at any time
234                         mHandler.sendMessageDelayed(msg, AppScanStats.SCAN_TIMEOUT_MS);
235                     }
236                 }
237 
238                 // Update BatteryStats with this workload.
239                 try {
240                     mBatteryStats.noteBleScanStarted(client.workSource);
241                 } catch (RemoteException e) {
242                     /* ignore */
243                 }
244             }
245         }
246 
handleStopScan(ScanClient client)247         void handleStopScan(ScanClient client) {
248             Utils.enforceAdminPermission(mService);
249             if (client == null) return;
250 
251             if (mRegularScanClients.contains(client)) {
252 
253                 mScanNative.stopRegularScan(client);
254 
255                 if (mScanNative.numRegularScanClients() == 0) {
256                     mHandler.removeMessages(MSG_SCAN_TIMEOUT);
257                 }
258 
259                 if (!mScanNative.isOpportunisticScanClient(client)) {
260                     mScanNative.configureRegularScanParams();
261                 }
262 
263                 // Update BatteryStats with this workload.
264                 try {
265                     // The ScanClient passed in just holds the clientIf. We retrieve the real client,
266                     // which may have workSource set.
267                     ScanClient workClient = mScanNative.getRegularScanClient(client.clientIf);
268                     if (workClient != null)
269                         mBatteryStats.noteBleScanStopped(workClient.workSource);
270                 } catch (RemoteException e) {
271                     /* ignore */
272                 }
273             } else {
274                 mScanNative.stopBatchScan(client);
275             }
276             if (client.appDied) {
277                 logd("app died, unregister client - " + client.clientIf);
278                 mService.unregisterClient(client.clientIf);
279             }
280         }
281 
handleFlushBatchResults(ScanClient client)282         void handleFlushBatchResults(ScanClient client) {
283             Utils.enforceAdminPermission(mService);
284             if (!mBatchClients.contains(client)) {
285                 return;
286             }
287             mScanNative.flushBatchResults(client.clientIf);
288         }
289 
isBatchClient(ScanClient client)290         private boolean isBatchClient(ScanClient client) {
291             if (client == null || client.settings == null) {
292                 return false;
293             }
294             ScanSettings settings = client.settings;
295             return settings.getCallbackType() == ScanSettings.CALLBACK_TYPE_ALL_MATCHES &&
296                     settings.getReportDelayMillis() != 0;
297         }
298 
isScanSupported(ScanClient client)299         private boolean isScanSupported(ScanClient client) {
300             if (client == null || client.settings == null) {
301                 return true;
302             }
303             ScanSettings settings = client.settings;
304             if (isFilteringSupported()) {
305                 return true;
306             }
307             return settings.getCallbackType() == ScanSettings.CALLBACK_TYPE_ALL_MATCHES &&
308                     settings.getReportDelayMillis() == 0;
309         }
310     }
311 
312     /**
313      * Parameters for batch scans.
314      */
315     class BatchScanParams {
316         int scanMode;
317         int fullScanClientIf;
318         int truncatedScanClientIf;
319 
BatchScanParams()320         BatchScanParams() {
321             scanMode = -1;
322             fullScanClientIf = -1;
323             truncatedScanClientIf = -1;
324         }
325 
326         @Override
equals(Object obj)327         public boolean equals(Object obj) {
328             if (this == obj) {
329                 return true;
330             }
331             if (obj == null || getClass() != obj.getClass()) {
332                 return false;
333             }
334             BatchScanParams other = (BatchScanParams) obj;
335             return scanMode == other.scanMode && fullScanClientIf == other.fullScanClientIf
336                     && truncatedScanClientIf == other.truncatedScanClientIf;
337 
338         }
339     }
340 
getCurrentUsedTrackingAdvertisement()341     public int getCurrentUsedTrackingAdvertisement() {
342         return curUsedTrackableAdvertisements;
343     }
344 
345     private class ScanNative {
346 
347         // Delivery mode defined in bt stack.
348         private static final int DELIVERY_MODE_IMMEDIATE = 0;
349         private static final int DELIVERY_MODE_ON_FOUND_LOST = 1;
350         private static final int DELIVERY_MODE_BATCH = 2;
351 
352         private static final int ONFOUND_SIGHTINGS_AGGRESSIVE = 1;
353         private static final int ONFOUND_SIGHTINGS_STICKY = 4;
354 
355         private static final int ALL_PASS_FILTER_INDEX_REGULAR_SCAN = 1;
356         private static final int ALL_PASS_FILTER_INDEX_BATCH_SCAN = 2;
357         private static final int ALL_PASS_FILTER_SELECTION = 0;
358 
359         private static final int DISCARD_OLDEST_WHEN_BUFFER_FULL = 0;
360 
361         /**
362          * Scan params corresponding to regular scan setting
363          */
364         private static final int SCAN_MODE_LOW_POWER_WINDOW_MS = 500;
365         private static final int SCAN_MODE_LOW_POWER_INTERVAL_MS = 5000;
366         private static final int SCAN_MODE_BALANCED_WINDOW_MS = 2000;
367         private static final int SCAN_MODE_BALANCED_INTERVAL_MS = 5000;
368         private static final int SCAN_MODE_LOW_LATENCY_WINDOW_MS = 5000;
369         private static final int SCAN_MODE_LOW_LATENCY_INTERVAL_MS = 5000;
370 
371         /**
372          * Onfound/onlost for scan settings
373          */
374         private static final int MATCH_MODE_AGGRESSIVE_TIMEOUT_FACTOR = (1);
375         private static final int MATCH_MODE_STICKY_TIMEOUT_FACTOR = (3);
376         private static final int ONLOST_FACTOR = 2;
377         private static final int ONLOST_ONFOUND_BASE_TIMEOUT_MS = 500;
378 
379         /**
380          * Scan params corresponding to batch scan setting
381          */
382         private static final int SCAN_MODE_BATCH_LOW_POWER_WINDOW_MS = 1500;
383         private static final int SCAN_MODE_BATCH_LOW_POWER_INTERVAL_MS = 150000;
384         private static final int SCAN_MODE_BATCH_BALANCED_WINDOW_MS = 1500;
385         private static final int SCAN_MODE_BATCH_BALANCED_INTERVAL_MS = 15000;
386         private static final int SCAN_MODE_BATCH_LOW_LATENCY_WINDOW_MS = 1500;
387         private static final int SCAN_MODE_BATCH_LOW_LATENCY_INTERVAL_MS = 5000;
388 
389         // The logic is AND for each filter field.
390         private static final int LIST_LOGIC_TYPE = 0x1111111;
391         private static final int FILTER_LOGIC_TYPE = 1;
392         // Filter indices that are available to user. It's sad we need to maintain filter index.
393         private final Deque<Integer> mFilterIndexStack;
394         // Map of clientIf and Filter indices used by client.
395         private final Map<Integer, Deque<Integer>> mClientFilterIndexMap;
396         // Keep track of the clients that uses ALL_PASS filters.
397         private final Set<Integer> mAllPassRegularClients = new HashSet<>();
398         private final Set<Integer> mAllPassBatchClients = new HashSet<>();
399 
400         private AlarmManager mAlarmManager;
401         private PendingIntent mBatchScanIntervalIntent;
402 
ScanNative()403         ScanNative() {
404             mFilterIndexStack = new ArrayDeque<Integer>();
405             mClientFilterIndexMap = new HashMap<Integer, Deque<Integer>>();
406 
407             mAlarmManager = (AlarmManager) mService.getSystemService(Context.ALARM_SERVICE);
408             Intent batchIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null);
409             mBatchScanIntervalIntent = PendingIntent.getBroadcast(mService, 0, batchIntent, 0);
410             IntentFilter filter = new IntentFilter();
411             filter.addAction(ACTION_REFRESH_BATCHED_SCAN);
412             mBatchAlarmReceiver = new BroadcastReceiver() {
413                     @Override
414                 public void onReceive(Context context, Intent intent) {
415                     Log.d(TAG, "awakened up at time " + SystemClock.elapsedRealtime());
416                     String action = intent.getAction();
417 
418                     if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) {
419                         if (mBatchClients.isEmpty()) {
420                             return;
421                         }
422                         // Note this actually flushes all pending batch data.
423                         flushBatchScanResults(mBatchClients.iterator().next());
424                     }
425                 }
426             };
427             mService.registerReceiver(mBatchAlarmReceiver, filter);
428             mBatchAlarmReceiverRegistered = true;
429         }
430 
resetCountDownLatch()431         private void resetCountDownLatch() {
432             mLatch = new CountDownLatch(1);
433         }
434 
435         // Returns true if mLatch reaches 0, false if timeout or interrupted.
waitForCallback()436         private boolean waitForCallback() {
437             try {
438                 return mLatch.await(OPERATION_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS);
439             } catch (InterruptedException e) {
440                 return false;
441             }
442         }
443 
configureRegularScanParams()444         void configureRegularScanParams() {
445             logd("configureRegularScanParams() - queue=" + mRegularScanClients.size());
446             int curScanSetting = Integer.MIN_VALUE;
447             ScanClient client = getAggressiveClient(mRegularScanClients);
448             if (client != null) {
449                 curScanSetting = client.settings.getScanMode();
450             }
451 
452             logd("configureRegularScanParams() - ScanSetting Scan mode=" + curScanSetting +
453                     " mLastConfiguredScanSetting=" + mLastConfiguredScanSetting);
454 
455             if (curScanSetting != Integer.MIN_VALUE &&
456                     curScanSetting != ScanSettings.SCAN_MODE_OPPORTUNISTIC) {
457                 if (curScanSetting != mLastConfiguredScanSetting) {
458                     int scanWindow = getScanWindowMillis(client.settings);
459                     int scanInterval = getScanIntervalMillis(client.settings);
460                     // convert scanWindow and scanInterval from ms to LE scan units(0.625ms)
461                     scanWindow = Utils.millsToUnit(scanWindow);
462                     scanInterval = Utils.millsToUnit(scanInterval);
463                     gattClientScanNative(false);
464                     logd("configureRegularScanParams - scanInterval = " + scanInterval +
465                         "configureRegularScanParams - scanWindow = " + scanWindow);
466                     gattSetScanParametersNative(client.clientIf, scanInterval, scanWindow);
467                     gattClientScanNative(true);
468                     mLastConfiguredScanSetting = curScanSetting;
469                 }
470             } else {
471                 mLastConfiguredScanSetting = curScanSetting;
472                 logd("configureRegularScanParams() - queue emtpy, scan stopped");
473             }
474         }
475 
getAggressiveClient(Set<ScanClient> cList)476         ScanClient getAggressiveClient(Set<ScanClient> cList) {
477             ScanClient result = null;
478             int curScanSetting = Integer.MIN_VALUE;
479             for (ScanClient client : cList) {
480                 // ScanClient scan settings are assumed to be monotonically increasing in value for
481                 // more power hungry(higher duty cycle) operation.
482                 if (client.settings.getScanMode() > curScanSetting) {
483                     result = client;
484                     curScanSetting = client.settings.getScanMode();
485                 }
486             }
487             return result;
488         }
489 
startRegularScan(ScanClient client)490         void startRegularScan(ScanClient client) {
491             if (isFilteringSupported() && mFilterIndexStack.isEmpty()
492                     && mClientFilterIndexMap.isEmpty()) {
493                 initFilterIndexStack();
494             }
495             if (isFilteringSupported()) {
496                 configureScanFilters(client);
497             }
498             // Start scan native only for the first client.
499             if (numRegularScanClients() == 1) {
500                 gattClientScanNative(true);
501             }
502         }
503 
numRegularScanClients()504         private int numRegularScanClients() {
505             int num = 0;
506             for (ScanClient client: mRegularScanClients) {
507                 if (client.settings.getScanMode() != ScanSettings.SCAN_MODE_OPPORTUNISTIC) {
508                     num++;
509                 }
510             }
511             return num;
512         }
513 
startBatchScan(ScanClient client)514         void startBatchScan(ScanClient client) {
515             if (mFilterIndexStack.isEmpty() && isFilteringSupported()) {
516                 initFilterIndexStack();
517             }
518             configureScanFilters(client);
519             if (!isOpportunisticScanClient(client)) {
520                 // Reset batch scan. May need to stop the existing batch scan and update scan params.
521                 resetBatchScan(client);
522             }
523         }
524 
isExemptFromScanDowngrade(ScanClient client)525         private boolean isExemptFromScanDowngrade(ScanClient client) {
526           return isOpportunisticScanClient(client)
527               || isFirstMatchScanClient(client)
528               || !shouldUseAllPassFilter(client);
529         }
530 
isOpportunisticScanClient(ScanClient client)531         private boolean isOpportunisticScanClient(ScanClient client) {
532             return client.settings.getScanMode() == ScanSettings.SCAN_MODE_OPPORTUNISTIC;
533         }
534 
isFirstMatchScanClient(ScanClient client)535         private boolean isFirstMatchScanClient(ScanClient client) {
536             return (client.settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0;
537         }
538 
resetBatchScan(ScanClient client)539         private void resetBatchScan(ScanClient client) {
540             int clientIf = client.clientIf;
541             BatchScanParams batchScanParams = getBatchScanParams();
542             // Stop batch if batch scan params changed and previous params is not null.
543             if (mBatchScanParms != null && (!mBatchScanParms.equals(batchScanParams))) {
544                 logd("stopping BLe Batch");
545                 resetCountDownLatch();
546                 gattClientStopBatchScanNative(clientIf);
547                 waitForCallback();
548                 // Clear pending results as it's illegal to config storage if there are still
549                 // pending results.
550                 flushBatchResults(clientIf);
551             }
552             // Start batch if batchScanParams changed and current params is not null.
553             if (batchScanParams != null && (!batchScanParams.equals(mBatchScanParms))) {
554                 int notifyThreshold = 95;
555                 logd("Starting BLE batch scan");
556                 int resultType = getResultType(batchScanParams);
557                 int fullScanPercent = getFullScanStoragePercent(resultType);
558                 resetCountDownLatch();
559                 logd("configuring batch scan storage, appIf " + client.clientIf);
560                 gattClientConfigBatchScanStorageNative(client.clientIf, fullScanPercent,
561                         100 - fullScanPercent, notifyThreshold);
562                 waitForCallback();
563                 resetCountDownLatch();
564                 int scanInterval =
565                         Utils.millsToUnit(getBatchScanIntervalMillis(batchScanParams.scanMode));
566                 int scanWindow =
567                         Utils.millsToUnit(getBatchScanWindowMillis(batchScanParams.scanMode));
568                 gattClientStartBatchScanNative(clientIf, resultType, scanInterval,
569                         scanWindow, 0, DISCARD_OLDEST_WHEN_BUFFER_FULL);
570                 waitForCallback();
571             }
572             mBatchScanParms = batchScanParams;
573             setBatchAlarm();
574         }
575 
getFullScanStoragePercent(int resultType)576         private int getFullScanStoragePercent(int resultType) {
577             switch (resultType) {
578                 case SCAN_RESULT_TYPE_FULL:
579                     return 100;
580                 case SCAN_RESULT_TYPE_TRUNCATED:
581                     return 0;
582                 case SCAN_RESULT_TYPE_BOTH:
583                     return 50;
584                 default:
585                     return 50;
586             }
587         }
588 
getBatchScanParams()589         private BatchScanParams getBatchScanParams() {
590             if (mBatchClients.isEmpty()) {
591                 return null;
592             }
593             BatchScanParams params = new BatchScanParams();
594             // TODO: split full batch scan results and truncated batch scan results to different
595             // collections.
596             for (ScanClient client : mBatchClients) {
597                 params.scanMode = Math.max(params.scanMode, client.settings.getScanMode());
598                 if (client.settings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_FULL) {
599                     params.fullScanClientIf = client.clientIf;
600                 } else {
601                     params.truncatedScanClientIf = client.clientIf;
602                 }
603             }
604             return params;
605         }
606 
getBatchScanWindowMillis(int scanMode)607         private int getBatchScanWindowMillis(int scanMode) {
608             switch (scanMode) {
609                 case ScanSettings.SCAN_MODE_LOW_LATENCY:
610                     return SCAN_MODE_BATCH_LOW_LATENCY_WINDOW_MS;
611                 case ScanSettings.SCAN_MODE_BALANCED:
612                     return SCAN_MODE_BATCH_BALANCED_WINDOW_MS;
613                 case ScanSettings.SCAN_MODE_LOW_POWER:
614                     return SCAN_MODE_BATCH_LOW_POWER_WINDOW_MS;
615                 default:
616                     return SCAN_MODE_BATCH_LOW_POWER_WINDOW_MS;
617             }
618         }
619 
getBatchScanIntervalMillis(int scanMode)620         private int getBatchScanIntervalMillis(int scanMode) {
621             switch (scanMode) {
622                 case ScanSettings.SCAN_MODE_LOW_LATENCY:
623                     return SCAN_MODE_BATCH_LOW_LATENCY_INTERVAL_MS;
624                 case ScanSettings.SCAN_MODE_BALANCED:
625                     return SCAN_MODE_BATCH_BALANCED_INTERVAL_MS;
626                 case ScanSettings.SCAN_MODE_LOW_POWER:
627                     return SCAN_MODE_BATCH_LOW_POWER_INTERVAL_MS;
628                 default:
629                     return SCAN_MODE_BATCH_LOW_POWER_INTERVAL_MS;
630             }
631         }
632 
633         // Set the batch alarm to be triggered within a short window after batch interval. This
634         // allows system to optimize wake up time while still allows a degree of precise control.
setBatchAlarm()635         private void setBatchAlarm() {
636             // Cancel any pending alarm just in case.
637             mAlarmManager.cancel(mBatchScanIntervalIntent);
638             if (mBatchClients.isEmpty()) {
639                 return;
640             }
641             long batchTriggerIntervalMillis = getBatchTriggerIntervalMillis();
642             // Allows the alarm to be triggered within
643             // [batchTriggerIntervalMillis, 1.1 * batchTriggerIntervalMillis]
644             long windowLengthMillis = batchTriggerIntervalMillis / 10;
645             long windowStartMillis = SystemClock.elapsedRealtime() + batchTriggerIntervalMillis;
646             mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
647                     windowStartMillis, windowLengthMillis,
648                     mBatchScanIntervalIntent);
649         }
650 
stopRegularScan(ScanClient client)651         void stopRegularScan(ScanClient client) {
652             // Remove scan filters and recycle filter indices.
653             if (client == null) return;
654             int deliveryMode = getDeliveryMode(client);
655             if (deliveryMode == DELIVERY_MODE_ON_FOUND_LOST) {
656                 for (ScanFilter filter : client.filters) {
657                     int entriesToFree = getNumOfTrackingAdvertisements(client.settings);
658                     if (!manageAllocationOfTrackingAdvertisement(entriesToFree, false)) {
659                         Log.e(TAG, "Error freeing for onfound/onlost filter resources "
660                                     + entriesToFree);
661                         try {
662                             mService.onScanManagerErrorCallback(client.clientIf,
663                                             ScanCallback.SCAN_FAILED_INTERNAL_ERROR);
664                         } catch (RemoteException e) {
665                             Log.e(TAG, "failed on onScanManagerCallback at freeing", e);
666                         }
667                     }
668                 }
669             }
670             mRegularScanClients.remove(client);
671             if (numRegularScanClients() == 0) {
672                 logd("stop scan");
673                 gattClientScanNative(false);
674             }
675             removeScanFilters(client.clientIf);
676         }
677 
regularScanTimeout(ScanClient client)678         void regularScanTimeout(ScanClient client) {
679             if (!isExemptFromScanDowngrade(client) && client.stats.isScanningTooLong()) {
680                 Log.w(TAG,
681                         "Moving scan client to opportunistic (clientIf " + client.clientIf + ")");
682                 setOpportunisticScanClient(client);
683                 client.stats.setScanTimeout();
684             }
685 
686             // The scan should continue for background scans
687             configureRegularScanParams();
688             if (numRegularScanClients() == 0) {
689                 logd("stop scan");
690                 gattClientScanNative(false);
691             }
692         }
693 
setOpportunisticScanClient(ScanClient client)694         void setOpportunisticScanClient(ScanClient client) {
695             // TODO: Add constructor to ScanSettings.Builder
696             // that can copy values from an existing ScanSettings object
697             ScanSettings.Builder builder = new ScanSettings.Builder();
698             ScanSettings settings = client.settings;
699             builder.setScanMode(ScanSettings.SCAN_MODE_OPPORTUNISTIC);
700             builder.setCallbackType(settings.getCallbackType());
701             builder.setScanResultType(settings.getScanResultType());
702             builder.setReportDelay(settings.getReportDelayMillis());
703             builder.setNumOfMatches(settings.getNumOfMatches());
704             client.settings = builder.build();
705         }
706 
707         // Find the regular scan client information.
getRegularScanClient(int clientIf)708         ScanClient getRegularScanClient(int clientIf) {
709             for (ScanClient client : mRegularScanClients) {
710               if (client.clientIf == clientIf) return client;
711             }
712             return null;
713         }
714 
stopBatchScan(ScanClient client)715         void stopBatchScan(ScanClient client) {
716             mBatchClients.remove(client);
717             removeScanFilters(client.clientIf);
718             if (!isOpportunisticScanClient(client)) {
719                 resetBatchScan(client);
720             }
721         }
722 
flushBatchResults(int clientIf)723         void flushBatchResults(int clientIf) {
724             logd("flushPendingBatchResults - clientIf = " + clientIf);
725             if (mBatchScanParms.fullScanClientIf != -1) {
726                 resetCountDownLatch();
727                 gattClientReadScanReportsNative(mBatchScanParms.fullScanClientIf,
728                         SCAN_RESULT_TYPE_FULL);
729                 waitForCallback();
730             }
731             if (mBatchScanParms.truncatedScanClientIf != -1) {
732                 resetCountDownLatch();
733                 gattClientReadScanReportsNative(mBatchScanParms.truncatedScanClientIf,
734                         SCAN_RESULT_TYPE_TRUNCATED);
735                 waitForCallback();
736             }
737             setBatchAlarm();
738         }
739 
cleanup()740         void cleanup() {
741             mAlarmManager.cancel(mBatchScanIntervalIntent);
742             // Protect against multiple calls of cleanup.
743             if (mBatchAlarmReceiverRegistered) {
744                 mService.unregisterReceiver(mBatchAlarmReceiver);
745             }
746             mBatchAlarmReceiverRegistered = false;
747         }
748 
getBatchTriggerIntervalMillis()749         private long getBatchTriggerIntervalMillis() {
750             long intervalMillis = Long.MAX_VALUE;
751             for (ScanClient client : mBatchClients) {
752                 if (client.settings != null && client.settings.getReportDelayMillis() > 0) {
753                     intervalMillis = Math.min(intervalMillis,
754                             client.settings.getReportDelayMillis());
755                 }
756             }
757             return intervalMillis;
758         }
759 
760         // Add scan filters. The logic is:
761         // If no offload filter can/needs to be set, set ALL_PASS filter.
762         // Otherwise offload all filters to hardware and enable all filters.
configureScanFilters(ScanClient client)763         private void configureScanFilters(ScanClient client) {
764             int clientIf = client.clientIf;
765             int deliveryMode = getDeliveryMode(client);
766             int trackEntries = 0;
767             if (!shouldAddAllPassFilterToController(client, deliveryMode)) {
768                 return;
769             }
770 
771             resetCountDownLatch();
772             gattClientScanFilterEnableNative(clientIf, true);
773             waitForCallback();
774 
775             if (shouldUseAllPassFilter(client)) {
776                 int filterIndex = (deliveryMode == DELIVERY_MODE_BATCH) ?
777                         ALL_PASS_FILTER_INDEX_BATCH_SCAN : ALL_PASS_FILTER_INDEX_REGULAR_SCAN;
778                 resetCountDownLatch();
779                 // Don't allow Onfound/onlost with all pass
780                 configureFilterParamter(clientIf, client, ALL_PASS_FILTER_SELECTION,
781                                 filterIndex, 0);
782                 waitForCallback();
783             } else {
784                 Deque<Integer> clientFilterIndices = new ArrayDeque<Integer>();
785                 for (ScanFilter filter : client.filters) {
786                     ScanFilterQueue queue = new ScanFilterQueue();
787                     queue.addScanFilter(filter);
788                     int featureSelection = queue.getFeatureSelection();
789                     int filterIndex = mFilterIndexStack.pop();
790                     while (!queue.isEmpty()) {
791                         resetCountDownLatch();
792                         addFilterToController(clientIf, queue.pop(), filterIndex);
793                         waitForCallback();
794                     }
795                     resetCountDownLatch();
796                     if (deliveryMode == DELIVERY_MODE_ON_FOUND_LOST) {
797                         trackEntries = getNumOfTrackingAdvertisements(client.settings);
798                         if (!manageAllocationOfTrackingAdvertisement(trackEntries, true)) {
799                             Log.e(TAG, "No hardware resources for onfound/onlost filter " +
800                                     trackEntries);
801                             try {
802                                 mService.onScanManagerErrorCallback(clientIf,
803                                             ScanCallback.SCAN_FAILED_INTERNAL_ERROR);
804                             } catch (RemoteException e) {
805                                 Log.e(TAG, "failed on onScanManagerCallback", e);
806                             }
807                         }
808                     }
809                     configureFilterParamter(clientIf, client, featureSelection, filterIndex,
810                                             trackEntries);
811                     waitForCallback();
812                     clientFilterIndices.add(filterIndex);
813                 }
814                 mClientFilterIndexMap.put(clientIf, clientFilterIndices);
815             }
816         }
817 
818         // Check whether the filter should be added to controller.
819         // Note only on ALL_PASS filter should be added.
shouldAddAllPassFilterToController(ScanClient client, int deliveryMode)820         private boolean shouldAddAllPassFilterToController(ScanClient client, int deliveryMode) {
821             // Not an ALL_PASS client, need to add filter.
822             if (!shouldUseAllPassFilter(client)) {
823                 return true;
824             }
825 
826             if (deliveryMode == DELIVERY_MODE_BATCH) {
827                 mAllPassBatchClients.add(client.clientIf);
828                 return mAllPassBatchClients.size() == 1;
829             } else {
830                 mAllPassRegularClients.add(client.clientIf);
831                 return mAllPassRegularClients.size() == 1;
832             }
833         }
834 
removeScanFilters(int clientIf)835         private void removeScanFilters(int clientIf) {
836             Deque<Integer> filterIndices = mClientFilterIndexMap.remove(clientIf);
837             if (filterIndices != null) {
838                 mFilterIndexStack.addAll(filterIndices);
839                 for (Integer filterIndex : filterIndices) {
840                     resetCountDownLatch();
841                     gattClientScanFilterParamDeleteNative(clientIf, filterIndex);
842                     waitForCallback();
843                 }
844             }
845             // Remove if ALL_PASS filters are used.
846             removeFilterIfExisits(mAllPassRegularClients, clientIf,
847                     ALL_PASS_FILTER_INDEX_REGULAR_SCAN);
848             removeFilterIfExisits(mAllPassBatchClients, clientIf,
849                     ALL_PASS_FILTER_INDEX_BATCH_SCAN);
850         }
851 
removeFilterIfExisits(Set<Integer> clients, int clientIf, int filterIndex)852         private void removeFilterIfExisits(Set<Integer> clients, int clientIf, int filterIndex) {
853             if (!clients.contains(clientIf)) {
854                 return;
855             }
856             clients.remove(clientIf);
857             // Remove ALL_PASS filter iff no app is using it.
858             if (clients.isEmpty()) {
859                 resetCountDownLatch();
860                 gattClientScanFilterParamDeleteNative(clientIf, filterIndex);
861                 waitForCallback();
862             }
863         }
864 
getBatchScanClient(int clientIf)865         private ScanClient getBatchScanClient(int clientIf) {
866             for (ScanClient client : mBatchClients) {
867                 if (client.clientIf == clientIf) {
868                     return client;
869                 }
870             }
871             return null;
872         }
873 
874         /**
875          * Return batch scan result type value defined in bt stack.
876          */
getResultType(BatchScanParams params)877         private int getResultType(BatchScanParams params) {
878             if (params.fullScanClientIf != -1 && params.truncatedScanClientIf != -1) {
879                 return SCAN_RESULT_TYPE_BOTH;
880             }
881             if (params.truncatedScanClientIf != -1) {
882                 return SCAN_RESULT_TYPE_TRUNCATED;
883             }
884             if (params.fullScanClientIf != -1) {
885                 return SCAN_RESULT_TYPE_FULL;
886             }
887             return -1;
888         }
889 
890         // Check if ALL_PASS filter should be used for the client.
shouldUseAllPassFilter(ScanClient client)891         private boolean shouldUseAllPassFilter(ScanClient client) {
892             if (client == null) {
893                 return true;
894             }
895             if (client.filters == null || client.filters.isEmpty()) {
896                 return true;
897             }
898             return client.filters.size() > mFilterIndexStack.size();
899         }
900 
addFilterToController(int clientIf, ScanFilterQueue.Entry entry, int filterIndex)901         private void addFilterToController(int clientIf, ScanFilterQueue.Entry entry,
902                 int filterIndex) {
903             logd("addFilterToController: " + entry.type);
904             switch (entry.type) {
905                 case ScanFilterQueue.TYPE_DEVICE_ADDRESS:
906                     logd("add address " + entry.address);
907                     gattClientScanFilterAddNative(clientIf, entry.type, filterIndex, 0, 0, 0, 0, 0,
908                             0,
909                             "", entry.address, (byte) entry.addr_type, new byte[0], new byte[0]);
910                     break;
911 
912                 case ScanFilterQueue.TYPE_SERVICE_DATA:
913                     gattClientScanFilterAddNative(clientIf, entry.type, filterIndex, 0, 0, 0, 0, 0,
914                             0,
915                             "", "", (byte) 0, entry.data, entry.data_mask);
916                     break;
917 
918                 case ScanFilterQueue.TYPE_SERVICE_UUID:
919                 case ScanFilterQueue.TYPE_SOLICIT_UUID:
920                     gattClientScanFilterAddNative(clientIf, entry.type, filterIndex, 0, 0,
921                             entry.uuid.getLeastSignificantBits(),
922                             entry.uuid.getMostSignificantBits(),
923                             entry.uuid_mask.getLeastSignificantBits(),
924                             entry.uuid_mask.getMostSignificantBits(),
925                             "", "", (byte) 0, new byte[0], new byte[0]);
926                     break;
927 
928                 case ScanFilterQueue.TYPE_LOCAL_NAME:
929                     logd("adding filters: " + entry.name);
930                     gattClientScanFilterAddNative(clientIf, entry.type, filterIndex, 0, 0, 0, 0, 0,
931                             0,
932                             entry.name, "", (byte) 0, new byte[0], new byte[0]);
933                     break;
934 
935                 case ScanFilterQueue.TYPE_MANUFACTURER_DATA:
936                     int len = entry.data.length;
937                     if (entry.data_mask.length != len)
938                         return;
939                     gattClientScanFilterAddNative(clientIf, entry.type, filterIndex, entry.company,
940                             entry.company_mask, 0, 0, 0, 0, "", "", (byte) 0,
941                             entry.data, entry.data_mask);
942                     break;
943             }
944         }
945 
initFilterIndexStack()946         private void initFilterIndexStack() {
947             int maxFiltersSupported =
948                     AdapterService.getAdapterService().getNumOfOffloadedScanFilterSupported();
949             // Start from index 3 as:
950             // index 0 is reserved for ALL_PASS filter in Settings app.
951             // index 1 is reserved for ALL_PASS filter for regular scan apps.
952             // index 2 is reserved for ALL_PASS filter for batch scan apps.
953             for (int i = 3; i < maxFiltersSupported; ++i) {
954                 mFilterIndexStack.add(i);
955             }
956         }
957 
958         // Configure filter parameters.
configureFilterParamter(int clientIf, ScanClient client, int featureSelection, int filterIndex, int numOfTrackingEntries)959         private void configureFilterParamter(int clientIf, ScanClient client, int featureSelection,
960                 int filterIndex, int numOfTrackingEntries) {
961             int deliveryMode = getDeliveryMode(client);
962             int rssiThreshold = Byte.MIN_VALUE;
963             ScanSettings settings = client.settings;
964             int onFoundTimeout = getOnFoundOnLostTimeoutMillis(settings, true);
965             int onLostTimeout = getOnFoundOnLostTimeoutMillis(settings, false);
966             int onFoundCount = getOnFoundOnLostSightings(settings);
967             onLostTimeout = 10000;
968             logd("configureFilterParamter " + onFoundTimeout + " " + onLostTimeout + " "
969                     + onFoundCount + " " + numOfTrackingEntries);
970             FilterParams FiltValue = new FilterParams(clientIf, filterIndex, featureSelection,
971                     LIST_LOGIC_TYPE, FILTER_LOGIC_TYPE, rssiThreshold, rssiThreshold, deliveryMode,
972                     onFoundTimeout, onLostTimeout, onFoundCount, numOfTrackingEntries);
973             gattClientScanFilterParamAddNative(FiltValue);
974         }
975 
976         // Get delivery mode based on scan settings.
getDeliveryMode(ScanClient client)977         private int getDeliveryMode(ScanClient client) {
978             if (client == null) {
979                 return DELIVERY_MODE_IMMEDIATE;
980             }
981             ScanSettings settings = client.settings;
982             if (settings == null) {
983                 return DELIVERY_MODE_IMMEDIATE;
984             }
985             if ((settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0
986                     || (settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_MATCH_LOST) != 0) {
987                 return DELIVERY_MODE_ON_FOUND_LOST;
988             }
989             return settings.getReportDelayMillis() == 0 ? DELIVERY_MODE_IMMEDIATE
990                     : DELIVERY_MODE_BATCH;
991         }
992 
getScanWindowMillis(ScanSettings settings)993         private int getScanWindowMillis(ScanSettings settings) {
994             if (settings == null) {
995                 return SCAN_MODE_LOW_POWER_WINDOW_MS;
996             }
997             switch (settings.getScanMode()) {
998                 case ScanSettings.SCAN_MODE_LOW_LATENCY:
999                     return SCAN_MODE_LOW_LATENCY_WINDOW_MS;
1000                 case ScanSettings.SCAN_MODE_BALANCED:
1001                     return SCAN_MODE_BALANCED_WINDOW_MS;
1002                 case ScanSettings.SCAN_MODE_LOW_POWER:
1003                     return SCAN_MODE_LOW_POWER_WINDOW_MS;
1004                 default:
1005                     return SCAN_MODE_LOW_POWER_WINDOW_MS;
1006             }
1007         }
1008 
getScanIntervalMillis(ScanSettings settings)1009         private int getScanIntervalMillis(ScanSettings settings) {
1010             if (settings == null)
1011                 return SCAN_MODE_LOW_POWER_INTERVAL_MS;
1012             switch (settings.getScanMode()) {
1013                 case ScanSettings.SCAN_MODE_LOW_LATENCY:
1014                     return SCAN_MODE_LOW_LATENCY_INTERVAL_MS;
1015                 case ScanSettings.SCAN_MODE_BALANCED:
1016                     return SCAN_MODE_BALANCED_INTERVAL_MS;
1017                 case ScanSettings.SCAN_MODE_LOW_POWER:
1018                     return SCAN_MODE_LOW_POWER_INTERVAL_MS;
1019                 default:
1020                     return SCAN_MODE_LOW_POWER_INTERVAL_MS;
1021             }
1022         }
1023 
getOnFoundOnLostTimeoutMillis(ScanSettings settings, boolean onFound)1024         private int getOnFoundOnLostTimeoutMillis(ScanSettings settings, boolean onFound) {
1025             int factor;
1026             int timeout = ONLOST_ONFOUND_BASE_TIMEOUT_MS;
1027 
1028             if (settings.getMatchMode() == ScanSettings.MATCH_MODE_AGGRESSIVE) {
1029                 factor = MATCH_MODE_AGGRESSIVE_TIMEOUT_FACTOR;
1030             } else {
1031                 factor = MATCH_MODE_STICKY_TIMEOUT_FACTOR;
1032             }
1033             if (!onFound) factor = factor * ONLOST_FACTOR;
1034             return (timeout*factor);
1035         }
1036 
getOnFoundOnLostSightings(ScanSettings settings)1037         private int getOnFoundOnLostSightings(ScanSettings settings) {
1038             if (settings == null)
1039                 return ONFOUND_SIGHTINGS_AGGRESSIVE;
1040             if (settings.getMatchMode() == ScanSettings.MATCH_MODE_AGGRESSIVE) {
1041                 return ONFOUND_SIGHTINGS_AGGRESSIVE;
1042             } else {
1043                 return ONFOUND_SIGHTINGS_STICKY;
1044             }
1045         }
1046 
getNumOfTrackingAdvertisements(ScanSettings settings)1047         private int getNumOfTrackingAdvertisements(ScanSettings settings) {
1048             if (settings == null)
1049                 return 0;
1050             int val=0;
1051             int maxTotalTrackableAdvertisements =
1052                     AdapterService.getAdapterService().getTotalNumOfTrackableAdvertisements();
1053             // controller based onfound onlost resources are scarce commodity; the
1054             // assignment of filters to num of beacons to track is configurable based
1055             // on hw capabilities. Apps give an intent and allocation of onfound
1056             // resources or failure there of is done based on availibility - FCFS model
1057             switch (settings.getNumOfMatches()) {
1058                 case ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT:
1059                     val = 1;
1060                     break;
1061                 case ScanSettings.MATCH_NUM_FEW_ADVERTISEMENT:
1062                     val = 2;
1063                     break;
1064                 case ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT:
1065                     val = maxTotalTrackableAdvertisements/2;
1066                     break;
1067                 default:
1068                     val = 1;
1069                     logd("Invalid setting for getNumOfMatches() " + settings.getNumOfMatches());
1070             }
1071             return val;
1072         }
1073 
manageAllocationOfTrackingAdvertisement(int numOfTrackableAdvertisement, boolean allocate)1074         private boolean manageAllocationOfTrackingAdvertisement(int numOfTrackableAdvertisement,
1075                             boolean allocate) {
1076             int maxTotalTrackableAdvertisements =
1077                     AdapterService.getAdapterService().getTotalNumOfTrackableAdvertisements();
1078             synchronized(curUsedTrackableAdvertisements) {
1079                 int availableEntries = maxTotalTrackableAdvertisements
1080                                             - curUsedTrackableAdvertisements;
1081                 if (allocate) {
1082                     if (availableEntries >= numOfTrackableAdvertisement) {
1083                         curUsedTrackableAdvertisements += numOfTrackableAdvertisement;
1084                         return true;
1085                     } else {
1086                         return false;
1087                     }
1088                 } else {
1089                     if (numOfTrackableAdvertisement > curUsedTrackableAdvertisements) {
1090                         return false;
1091                     } else {
1092                          curUsedTrackableAdvertisements -= numOfTrackableAdvertisement;
1093                          return true;
1094                     }
1095                 }
1096             }
1097         }
1098 
1099 
1100         /************************** Regular scan related native methods **************************/
gattClientScanNative(boolean start)1101         private native void gattClientScanNative(boolean start);
1102 
gattSetScanParametersNative(int client_if, int scan_interval, int scan_window)1103         private native void gattSetScanParametersNative(int client_if, int scan_interval,
1104                 int scan_window);
1105 
1106         /************************** Filter related native methods ********************************/
gattClientScanFilterAddNative(int client_if, int filter_type, int filter_index, int company_id, int company_id_mask, long uuid_lsb, long uuid_msb, long uuid_mask_lsb, long uuid_mask_msb, String name, String address, byte addr_type, byte[] data, byte[] mask)1107         private native void gattClientScanFilterAddNative(int client_if,
1108                 int filter_type, int filter_index, int company_id,
1109                 int company_id_mask, long uuid_lsb, long uuid_msb,
1110                 long uuid_mask_lsb, long uuid_mask_msb, String name,
1111                 String address, byte addr_type, byte[] data, byte[] mask);
1112 
gattClientScanFilterDeleteNative(int client_if, int filter_type, int filter_index, int company_id, int company_id_mask, long uuid_lsb, long uuid_msb, long uuid_mask_lsb, long uuid_mask_msb, String name, String address, byte addr_type, byte[] data, byte[] mask)1113         private native void gattClientScanFilterDeleteNative(int client_if,
1114                 int filter_type, int filter_index, int company_id,
1115                 int company_id_mask, long uuid_lsb, long uuid_msb,
1116                 long uuid_mask_lsb, long uuid_mask_msb, String name,
1117                 String address, byte addr_type, byte[] data, byte[] mask);
1118 
gattClientScanFilterParamAddNative(FilterParams FiltValue)1119         private native void gattClientScanFilterParamAddNative(FilterParams FiltValue);
1120 
1121         // Note this effectively remove scan filters for ALL clients.
gattClientScanFilterParamClearAllNative( int client_if)1122         private native void gattClientScanFilterParamClearAllNative(
1123                 int client_if);
1124 
gattClientScanFilterParamDeleteNative( int client_if, int filt_index)1125         private native void gattClientScanFilterParamDeleteNative(
1126                 int client_if, int filt_index);
1127 
gattClientScanFilterClearNative(int client_if, int filter_index)1128         private native void gattClientScanFilterClearNative(int client_if,
1129                 int filter_index);
1130 
gattClientScanFilterEnableNative(int client_if, boolean enable)1131         private native void gattClientScanFilterEnableNative(int client_if,
1132                 boolean enable);
1133 
1134         /************************** Batch related native methods *********************************/
gattClientConfigBatchScanStorageNative(int client_if, int max_full_reports_percent, int max_truncated_reports_percent, int notify_threshold_percent)1135         private native void gattClientConfigBatchScanStorageNative(int client_if,
1136                 int max_full_reports_percent, int max_truncated_reports_percent,
1137                 int notify_threshold_percent);
1138 
gattClientStartBatchScanNative(int client_if, int scan_mode, int scan_interval_unit, int scan_window_unit, int address_type, int discard_rule)1139         private native void gattClientStartBatchScanNative(int client_if, int scan_mode,
1140                 int scan_interval_unit, int scan_window_unit, int address_type, int discard_rule);
1141 
gattClientStopBatchScanNative(int client_if)1142         private native void gattClientStopBatchScanNative(int client_if);
1143 
gattClientReadScanReportsNative(int client_if, int scan_type)1144         private native void gattClientReadScanReportsNative(int client_if, int scan_type);
1145     }
1146 
logd(String s)1147     private void logd(String s) {
1148         if (DBG) Log.d(TAG, s);
1149     }
1150 }
1151