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