16d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang/*
26d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * Copyright (C) 2014 The Android Open Source Project
36d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang *
46d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * Licensed under the Apache License, Version 2.0 (the "License"); you may not
56d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * use this file except in compliance with the License. You may obtain a copy of
66d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * the License at
76d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang *
86d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * http://www.apache.org/licenses/LICENSE-2.0
96d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang *
106d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * Unless required by applicable law or agreed to in writing, software
116d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
126d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
136d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * License for the specific language governing permissions and limitations under
146d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * the License.
156d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang */
166d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
176d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangpackage android.bluetooth.le;
186d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
192d49752ee050ab7f1cd848933f6c62a73707e2d9Tor Norbyeimport android.Manifest;
20461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasaniimport android.annotation.NonNull;
21461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasaniimport android.annotation.Nullable;
222d49752ee050ab7f1cd848933f6c62a73707e2d9Tor Norbyeimport android.annotation.RequiresPermission;
230d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wangimport android.annotation.SystemApi;
24a179030483a1f3f672be41797dc6e0f077ef4748Fyodor Kupolovimport android.app.ActivityThread;
25461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasaniimport android.app.PendingIntent;
266d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangimport android.bluetooth.BluetoothAdapter;
276d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangimport android.bluetooth.BluetoothGatt;
286d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangimport android.bluetooth.IBluetoothGatt;
299fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wangimport android.bluetooth.IBluetoothManager;
306d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangimport android.os.Handler;
316d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangimport android.os.Looper;
326d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangimport android.os.RemoteException;
336771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinskiimport android.os.WorkSource;
346d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangimport android.util.Log;
356d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
360d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wangimport java.util.ArrayList;
376d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangimport java.util.HashMap;
386d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangimport java.util.List;
396d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangimport java.util.Map;
406d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
416d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang/**
426d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * This class provides methods to perform scan related operations for Bluetooth LE devices. An
43e7b03631d2a64c3ad5a739cedfd7d40fe5421844Scott Kennedy * application can scan for a particular type of Bluetooth LE devices using {@link ScanFilter}. It
44685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang * can also request different types of callbacks for delivering the result.
456d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * <p>
466d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * Use {@link BluetoothAdapter#getBluetoothLeScanner()} to get an instance of
476d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * {@link BluetoothLeScanner}.
486d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * <p>
49af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang * <b>Note:</b> Most of the scan methods here require
50af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
516d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang *
526d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * @see ScanFilter
536d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang */
546d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangpublic final class BluetoothLeScanner {
556d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
566d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private static final String TAG = "BluetoothLeScanner";
576d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private static final boolean DBG = true;
58020bd7b861dfd560fad9f761f2778ebbac8be20eWei Wang    private static final boolean VDBG = false;
596d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
60461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani    /**
61461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * Extra containing a list of ScanResults. It can have one or more results if there was no
62461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * error. In case of error, {@link #EXTRA_ERROR_CODE} will contain the error code and this
63461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * extra will not be available.
64461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     */
65461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani    public static final String EXTRA_LIST_SCAN_RESULT
66461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani            = "android.bluetooth.le.extra.LIST_SCAN_RESULT";
67461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani
68461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani    /**
69461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * Optional extra indicating the error code, if any. The error code will be one of the
70461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * SCAN_FAILED_* codes in {@link ScanCallback}.
71461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     */
72461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani    public static final String EXTRA_ERROR_CODE = "android.bluetooth.le.extra.ERROR_CODE";
73461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani
74461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani    /**
75461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * Optional extra indicating the callback type, which will be one of
76ad8f0869127bbc514711e4765703392b15e3c31aAmith Yamasani     * CALLBACK_TYPE_* constants in {@link ScanSettings}.
77461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * @see ScanCallback#onScanResult(int, ScanResult)
78461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     */
79461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani    public static final String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE";
80461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani
819fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang    private final IBluetoothManager mBluetoothManager;
826d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private final Handler mHandler;
838e5270fdf5639461d67e9a898a85520abac6053dPrerepa Viswanadham    private BluetoothAdapter mBluetoothAdapter;
846d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private final Map<ScanCallback, BleScanCallbackWrapper> mLeScanClients;
856d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
866d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    /**
87af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang     * Use {@link BluetoothAdapter#getBluetoothLeScanner()} instead.
88685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang     *
89685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang     * @param bluetoothManager BluetoothManager that conducts overall Bluetooth Management.
906d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * @hide
916d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     */
929fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang    public BluetoothLeScanner(IBluetoothManager bluetoothManager) {
939fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang        mBluetoothManager = bluetoothManager;
948e5270fdf5639461d67e9a898a85520abac6053dPrerepa Viswanadham        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
956d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        mHandler = new Handler(Looper.getMainLooper());
966d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        mLeScanClients = new HashMap<ScanCallback, BleScanCallbackWrapper>();
976d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    }
986d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
996d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    /**
100685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang     * Start Bluetooth LE scan with default parameters and no filters. The scan results will be
101685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang     * delivered through {@code callback}.
102af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang     * <p>
1037bd8be0019cb5896c27d0a2d39be19274c442ba5Fyodor Kupolov     * An app must hold
1047bd8be0019cb5896c27d0a2d39be19274c442ba5Fyodor Kupolov     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
1057bd8be0019cb5896c27d0a2d39be19274c442ba5Fyodor Kupolov     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
1067bd8be0019cb5896c27d0a2d39be19274c442ba5Fyodor Kupolov     * in order to get results.
107af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang     *
108af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang     * @param callback Callback used to deliver scan results.
109af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang     * @throws IllegalArgumentException If {@code callback} is null.
110af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang     */
1112d49752ee050ab7f1cd848933f6c62a73707e2d9Tor Norbye    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
112af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang    public void startScan(final ScanCallback callback) {
113833559d9f3f0bd6ddb1cf9c1571975751830e045Wei Wang        startScan(null, new ScanSettings.Builder().build(), callback);
114af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang    }
115af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang
116af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang    /**
1176d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * Start Bluetooth LE scan. The scan results will be delivered through {@code callback}.
1186d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * <p>
1197bd8be0019cb5896c27d0a2d39be19274c442ba5Fyodor Kupolov     * An app must hold
1207bd8be0019cb5896c27d0a2d39be19274c442ba5Fyodor Kupolov     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
1217bd8be0019cb5896c27d0a2d39be19274c442ba5Fyodor Kupolov     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
1227bd8be0019cb5896c27d0a2d39be19274c442ba5Fyodor Kupolov     * in order to get results.
1236d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     *
1246d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * @param filters {@link ScanFilter}s for finding exact BLE devices.
125af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang     * @param settings Settings for the scan.
126af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang     * @param callback Callback used to deliver scan results.
1276d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * @throws IllegalArgumentException If {@code settings} or {@code callback} is null.
1286d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     */
1292d49752ee050ab7f1cd848933f6c62a73707e2d9Tor Norbye    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
1306d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    public void startScan(List<ScanFilter> filters, ScanSettings settings,
1316d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            final ScanCallback callback) {
132461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani        startScan(filters, settings, null, callback, /*callbackIntent=*/ null, null);
133461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani    }
134461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani
135461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani    /**
136461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * Start Bluetooth LE scan using a {@link PendingIntent}. The scan results will be delivered via
137461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * the PendingIntent. Use this method of scanning if your process is not always running and it
138461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * should be started when scan results are available.
1399622137f3f5766408c82752f50a3dd8af6cd2134Amith Yamasani     * <p>
140172dd5c652af9b9bb52392799b3b0da99231beb5Amith Yamasani     * An app must hold
141172dd5c652af9b9bb52392799b3b0da99231beb5Amith Yamasani     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
142172dd5c652af9b9bb52392799b3b0da99231beb5Amith Yamasani     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
143172dd5c652af9b9bb52392799b3b0da99231beb5Amith Yamasani     * in order to get results.
144172dd5c652af9b9bb52392799b3b0da99231beb5Amith Yamasani     * <p>
1459622137f3f5766408c82752f50a3dd8af6cd2134Amith Yamasani     * When the PendingIntent is delivered, the Intent passed to the receiver or activity
1469622137f3f5766408c82752f50a3dd8af6cd2134Amith Yamasani     * will contain one or more of the extras {@link #EXTRA_CALLBACK_TYPE},
1479622137f3f5766408c82752f50a3dd8af6cd2134Amith Yamasani     * {@link #EXTRA_ERROR_CODE} and {@link #EXTRA_LIST_SCAN_RESULT} to indicate the result of
1489622137f3f5766408c82752f50a3dd8af6cd2134Amith Yamasani     * the scan.
149461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     *
150461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * @param filters Optional list of ScanFilters for finding exact BLE devices.
151461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * @param settings Optional settings for the scan.
152461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * @param callbackIntent The PendingIntent to deliver the result to.
153461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * @return Returns 0 for success or an error code from {@link ScanCallback} if the scan request
154461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * could not be sent.
155461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * @see #stopScan(PendingIntent)
156461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     */
157461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
158461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani    public int startScan(@Nullable List<ScanFilter> filters, @Nullable ScanSettings settings,
159461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani            @NonNull PendingIntent callbackIntent) {
160461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani        return startScan(filters,
161461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani                settings != null ? settings : new ScanSettings.Builder().build(),
162461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani                null, null, callbackIntent, null);
1636771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski    }
1646771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski
1656771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski    /**
1666771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski     * Start Bluetooth LE scan. Same as {@link #startScan(ScanCallback)} but allows the caller to
1676771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski     * specify on behalf of which application(s) the work is being done.
1686771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski     *
1696771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski     * @param workSource {@link WorkSource} identifying the application(s) for which to blame for
1706771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski     *                   the scan.
1716771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski     * @param callback Callback used to deliver scan results.
1726771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski     * @hide
1736771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski     */
1746771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski    @SystemApi
1756771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski    @RequiresPermission(allOf = {
1766771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski            Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.UPDATE_DEVICE_STATS })
1776771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski    public void startScanFromSource(final WorkSource workSource, final ScanCallback callback) {
1786771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski        startScanFromSource(null, new ScanSettings.Builder().build(), workSource, callback);
1796771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski    }
1806771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski
1816771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski    /**
1826771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski     * Start Bluetooth LE scan. Same as {@link #startScan(List, ScanSettings, ScanCallback)} but
1836771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski     * allows the caller to specify on behalf of which application(s) the work is being done.
1846771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski     *
1856771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski     * @param filters {@link ScanFilter}s for finding exact BLE devices.
1866771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski     * @param settings Settings for the scan.
1876771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski     * @param workSource {@link WorkSource} identifying the application(s) for which to blame for
1886771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski     *                   the scan.
1896771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski     * @param callback Callback used to deliver scan results.
1906771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski     * @hide
1916771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski     */
1926771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski    @SystemApi
1936771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski    @RequiresPermission(allOf = {
1946771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski            Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.UPDATE_DEVICE_STATS })
1956771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski    public void startScanFromSource(List<ScanFilter> filters, ScanSettings settings,
1966771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski                                    final WorkSource workSource, final ScanCallback callback) {
197461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani        startScan(filters, settings, workSource, callback, null, null);
1980d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang    }
1990d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang
200461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani    private int startScan(List<ScanFilter> filters, ScanSettings settings,
2016771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski                           final WorkSource workSource, final ScanCallback callback,
202461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani                           final PendingIntent callbackIntent,
2036771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski                           List<List<ResultStorageDescriptor>> resultStorages) {
204833559d9f3f0bd6ddb1cf9c1571975751830e045Wei Wang        BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
205461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani        if (callback == null && callbackIntent == null) {
2066771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski            throw new IllegalArgumentException("callback is null");
2076771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski        }
2086771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski        if (settings == null) {
2096771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski            throw new IllegalArgumentException("settings is null");
2106d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        }
2116d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        synchronized (mLeScanClients) {
212461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani            if (callback != null && mLeScanClients.containsKey(callback)) {
2139722971cb4a79e37165f636f9dd057707d2e620aVinay Kalia                return postCallbackErrorOrReturn(callback,
2149722971cb4a79e37165f636f9dd057707d2e620aVinay Kalia                            ScanCallback.SCAN_FAILED_ALREADY_STARTED);
2156d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            }
2169fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            IBluetoothGatt gatt;
2179fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            try {
2189fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang                gatt = mBluetoothManager.getBluetoothGatt();
2199fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            } catch (RemoteException e) {
2209fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang                gatt = null;
2219fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            }
2229fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            if (gatt == null) {
223461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani                return postCallbackErrorOrReturn(callback, ScanCallback.SCAN_FAILED_INTERNAL_ERROR);
2249fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            }
2258e5270fdf5639461d67e9a898a85520abac6053dPrerepa Viswanadham            if (!isSettingsConfigAllowedForScan(settings)) {
226461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani                return postCallbackErrorOrReturn(callback,
227461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani                            ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED);
2288e5270fdf5639461d67e9a898a85520abac6053dPrerepa Viswanadham            }
229e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham            if (!isHardwareResourcesAvailableForScan(settings)) {
230461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani                return postCallbackErrorOrReturn(callback,
231461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani                            ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES);
232e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham            }
233e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham            if (!isSettingsAndFilterComboAllowed(settings, filters)) {
234461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani                return postCallbackErrorOrReturn(callback,
235e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham                        ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED);
236e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham            }
237461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani            if (callback != null) {
238461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani                BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters,
239461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani                        settings, workSource, callback, resultStorages);
240461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani                wrapper.startRegistration();
241461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani            } else {
242461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani                try {
243461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani                    gatt.startScanForIntent(callbackIntent, settings, filters,
244461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani                            ActivityThread.currentOpPackageName());
245461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani                } catch (RemoteException e) {
246461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani                    return ScanCallback.SCAN_FAILED_INTERNAL_ERROR;
247461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani                }
248461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani            }
2496d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        }
250461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani        return ScanCallback.NO_ERROR;
2516d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    }
2526d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
2536d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    /**
2546d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * Stops an ongoing Bluetooth LE scan.
2556d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     *
2566d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * @param callback
2576d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     */
2582d49752ee050ab7f1cd848933f6c62a73707e2d9Tor Norbye    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
2596d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    public void stopScan(ScanCallback callback) {
260833559d9f3f0bd6ddb1cf9c1571975751830e045Wei Wang        BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
2616d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        synchronized (mLeScanClients) {
2626d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            BleScanCallbackWrapper wrapper = mLeScanClients.remove(callback);
2636d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            if (wrapper == null) {
264b661bb79584f83ae95713e502fc14363c80c0278Wei Wang                if (DBG) Log.d(TAG, "could not find callback wrapper");
2656d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                return;
2666d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            }
2676d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            wrapper.stopLeScan();
2686d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        }
2696d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    }
2706d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
2716d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    /**
272461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * Stops an ongoing Bluetooth LE scan started using a PendingIntent.
273461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     *
274461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * @param callbackIntent The PendingIntent that was used to start the scan.
275461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     * @see #startScan(List, ScanSettings, PendingIntent)
276461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani     */
277461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
278461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani    public void stopScan(PendingIntent callbackIntent) {
279461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani        BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
280461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani        IBluetoothGatt gatt;
281461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani        try {
282461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani            gatt = mBluetoothManager.getBluetoothGatt();
283461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani            gatt.stopScanForIntent(callbackIntent, ActivityThread.currentOpPackageName());
284461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani        } catch (RemoteException e) {
285461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani        }
286461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani    }
287461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani
288461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani    /**
2899fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang     * Flush pending batch scan results stored in Bluetooth controller. This will return Bluetooth
2909fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang     * LE scan results batched on bluetooth controller. Returns immediately, batch scan results data
2919fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang     * will be delivered through the {@code callback}.
2926d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     *
2936d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * @param callback Callback of the Bluetooth LE Scan, it has to be the same instance as the one
2946d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     *            used to start scan.
2956d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     */
2969fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang    public void flushPendingScanResults(ScanCallback callback) {
297833559d9f3f0bd6ddb1cf9c1571975751830e045Wei Wang        BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
2989fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang        if (callback == null) {
2999fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            throw new IllegalArgumentException("callback cannot be null!");
3009fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang        }
3019fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang        synchronized (mLeScanClients) {
3029fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            BleScanCallbackWrapper wrapper = mLeScanClients.get(callback);
3039fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            if (wrapper == null) {
3049fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang                return;
3059fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            }
3069fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            wrapper.flushPendingBatchResults();
3079fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang        }
3086d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    }
3096d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
3106d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    /**
3110d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang     * Start truncated scan.
3120d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang     *
3130d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang     * @hide
3140d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang     */
3150d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang    @SystemApi
3160d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang    public void startTruncatedScan(List<TruncatedFilter> truncatedFilters, ScanSettings settings,
3170d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang            final ScanCallback callback) {
3180d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang        int filterSize = truncatedFilters.size();
3190d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang        List<ScanFilter> scanFilters = new ArrayList<ScanFilter>(filterSize);
3200d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang        List<List<ResultStorageDescriptor>> scanStorages =
3210d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang                new ArrayList<List<ResultStorageDescriptor>>(filterSize);
3220d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang        for (TruncatedFilter filter : truncatedFilters) {
3230d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang            scanFilters.add(filter.getFilter());
3240d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang            scanStorages.add(filter.getStorageDescriptors());
3250d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang        }
326461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani        startScan(scanFilters, settings, null, callback, null, scanStorages);
3270d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang    }
3280d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang
3290d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang    /**
330ee80922c6a1228886589dcd4598a1cadf0bd1ff8Wei Wang     * Cleans up scan clients. Should be called when bluetooth is down.
331ee80922c6a1228886589dcd4598a1cadf0bd1ff8Wei Wang     *
332ee80922c6a1228886589dcd4598a1cadf0bd1ff8Wei Wang     * @hide
333ee80922c6a1228886589dcd4598a1cadf0bd1ff8Wei Wang     */
334ee80922c6a1228886589dcd4598a1cadf0bd1ff8Wei Wang    public void cleanup() {
335ee80922c6a1228886589dcd4598a1cadf0bd1ff8Wei Wang        mLeScanClients.clear();
336ee80922c6a1228886589dcd4598a1cadf0bd1ff8Wei Wang    }
337ee80922c6a1228886589dcd4598a1cadf0bd1ff8Wei Wang
338ee80922c6a1228886589dcd4598a1cadf0bd1ff8Wei Wang    /**
3396d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * Bluetooth GATT interface callbacks
3406d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     */
3411b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski    private class BleScanCallbackWrapper extends IScannerCallback.Stub {
342b661bb79584f83ae95713e502fc14363c80c0278Wei Wang        private static final int REGISTRATION_CALLBACK_TIMEOUT_MILLIS = 2000;
3436d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
3446d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        private final ScanCallback mScanCallback;
3456d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        private final List<ScanFilter> mFilters;
3466771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski        private final WorkSource mWorkSource;
3476d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        private ScanSettings mSettings;
3486d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        private IBluetoothGatt mBluetoothGatt;
3490d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang        private List<List<ResultStorageDescriptor>> mResultStorages;
3506d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
3516d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        // mLeHandle 0: not registered
352f50749040421edfdf22326b1e0f0568e4408fa26Jakub Pawlowski        // -2: registration failed because app is scanning to frequently
35302bc0086071b5faff260566b4d3713861703eee3Wei Wang        // -1: scan stopped or registration failed
3546d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        // > 0: registered and scan started
3551b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski        private int mScannerId;
3566d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
3576d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        public BleScanCallbackWrapper(IBluetoothGatt bluetoothGatt,
3586d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                List<ScanFilter> filters, ScanSettings settings,
3596771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski                WorkSource workSource, ScanCallback scanCallback,
3606771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski                List<List<ResultStorageDescriptor>> resultStorages) {
3616d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            mBluetoothGatt = bluetoothGatt;
3626d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            mFilters = filters;
3636d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            mSettings = settings;
3646771d629b5ad0b9296f0febaa2300fdaf1f90515Adam Lesinski            mWorkSource = workSource;
3656d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            mScanCallback = scanCallback;
3661b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski            mScannerId = 0;
3670d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang            mResultStorages = resultStorages;
3686d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        }
3696d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
370461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani        public void startRegistration() {
3716d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            synchronized (this) {
372b661bb79584f83ae95713e502fc14363c80c0278Wei Wang                // Scan stopped.
373f50749040421edfdf22326b1e0f0568e4408fa26Jakub Pawlowski                if (mScannerId == -1 || mScannerId == -2) return;
3746d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                try {
375a71643e91c46efa49a906e3d59f126c752d750b0Ajay Panicker                    mBluetoothGatt.registerScanner(this, mWorkSource);
376b661bb79584f83ae95713e502fc14363c80c0278Wei Wang                    wait(REGISTRATION_CALLBACK_TIMEOUT_MILLIS);
377b661bb79584f83ae95713e502fc14363c80c0278Wei Wang                } catch (InterruptedException | RemoteException e) {
378b661bb79584f83ae95713e502fc14363c80c0278Wei Wang                    Log.e(TAG, "application registeration exception", e);
379b661bb79584f83ae95713e502fc14363c80c0278Wei Wang                    postCallbackError(mScanCallback, ScanCallback.SCAN_FAILED_INTERNAL_ERROR);
380b661bb79584f83ae95713e502fc14363c80c0278Wei Wang                }
3811b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                if (mScannerId > 0) {
382b661bb79584f83ae95713e502fc14363c80c0278Wei Wang                    mLeScanClients.put(mScanCallback, this);
383b661bb79584f83ae95713e502fc14363c80c0278Wei Wang                } else {
3841b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                    // Registration timed out or got exception, reset scannerId to -1 so no
38502bc0086071b5faff260566b4d3713861703eee3Wei Wang                    // subsequent operations can proceed.
3861b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                    if (mScannerId == 0) mScannerId = -1;
387f50749040421edfdf22326b1e0f0568e4408fa26Jakub Pawlowski
388f50749040421edfdf22326b1e0f0568e4408fa26Jakub Pawlowski                    // If scanning too frequently, don't report anything to the app.
389f50749040421edfdf22326b1e0f0568e4408fa26Jakub Pawlowski                    if (mScannerId == -2) return;
390f50749040421edfdf22326b1e0f0568e4408fa26Jakub Pawlowski
391b661bb79584f83ae95713e502fc14363c80c0278Wei Wang                    postCallbackError(mScanCallback,
392b661bb79584f83ae95713e502fc14363c80c0278Wei Wang                            ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED);
3936d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                }
3946d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            }
3956d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        }
3966d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
3976d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        public void stopLeScan() {
3986d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            synchronized (this) {
3991b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                if (mScannerId <= 0) {
4001b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                    Log.e(TAG, "Error state, mLeHandle: " + mScannerId);
4016d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    return;
4026d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                }
4036d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                try {
4041b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                    mBluetoothGatt.stopScan(mScannerId);
4051b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                    mBluetoothGatt.unregisterScanner(mScannerId);
4066d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                } catch (RemoteException e) {
4079fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang                    Log.e(TAG, "Failed to stop scan and unregister", e);
4086d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                }
4091b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                mScannerId = -1;
4106d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            }
4116d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        }
4126d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
4139fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang        void flushPendingBatchResults() {
4149fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            synchronized (this) {
4151b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                if (mScannerId <= 0) {
4161b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                    Log.e(TAG, "Error state, mLeHandle: " + mScannerId);
4179fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang                    return;
4189fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang                }
4199fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang                try {
4201b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                    mBluetoothGatt.flushPendingBatchResults(mScannerId);
4219fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang                } catch (RemoteException e) {
4229fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang                    Log.e(TAG, "Failed to get pending scan results", e);
4239fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang                }
4249fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            }
4259fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang        }
4269fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang
4276d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        /**
4286d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang         * Application interface registered - app is ready to go
4296d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang         */
4306d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        @Override
4311b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski        public void onScannerRegistered(int status, int scannerId) {
4321b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski            Log.d(TAG, "onScannerRegistered() - status=" + status +
4331b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                    " scannerId=" + scannerId + " mScannerId=" + mScannerId);
4346d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            synchronized (this) {
4356d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                if (status == BluetoothGatt.GATT_SUCCESS) {
4366d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    try {
4371b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                        if (mScannerId == -1) {
43802bc0086071b5faff260566b4d3713861703eee3Wei Wang                            // Registration succeeds after timeout, unregister client.
4391b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                            mBluetoothGatt.unregisterClient(scannerId);
44002bc0086071b5faff260566b4d3713861703eee3Wei Wang                        } else {
4411b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                            mScannerId = scannerId;
4421b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                            mBluetoothGatt.startScan(mScannerId, mSettings, mFilters,
443a71643e91c46efa49a906e3d59f126c752d750b0Ajay Panicker                                    mResultStorages,
44402bc0086071b5faff260566b4d3713861703eee3Wei Wang                                    ActivityThread.currentOpPackageName());
44502bc0086071b5faff260566b4d3713861703eee3Wei Wang                        }
4466d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    } catch (RemoteException e) {
4476d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        Log.e(TAG, "fail to start le scan: " + e);
4481b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                        mScannerId = -1;
4496d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    }
450f50749040421edfdf22326b1e0f0568e4408fa26Jakub Pawlowski                } else if (status == ScanCallback.SCAN_FAILED_SCANNING_TOO_FREQUENTLY) {
451f50749040421edfdf22326b1e0f0568e4408fa26Jakub Pawlowski                    // applicaiton was scanning too frequently
452f50749040421edfdf22326b1e0f0568e4408fa26Jakub Pawlowski                    mScannerId = -2;
4536d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                } else {
4546d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    // registration failed
4551b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                    mScannerId = -1;
4566d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                }
4576d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                notifyAll();
4586d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            }
4596d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        }
4606d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
4616d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        /**
4626d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang         * Callback reporting an LE scan result.
4636d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang         *
4646d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang         * @hide
4656d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang         */
4666d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        @Override
467e0d4afb2d4caecb264852a35f6e3cfc1248e08c4Wei Wang        public void onScanResult(final ScanResult scanResult) {
468020bd7b861dfd560fad9f761f2778ebbac8be20eWei Wang            if (VDBG) Log.d(TAG, "onScanResult() - " + scanResult.toString());
4696d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
4706d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            // Check null in case the scan has been stopped
4716d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            synchronized (this) {
4721b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                if (mScannerId <= 0) return;
4736d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            }
4749fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            Handler handler = new Handler(Looper.getMainLooper());
4759fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            handler.post(new Runnable() {
476b661bb79584f83ae95713e502fc14363c80c0278Wei Wang                @Override
4779fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang                public void run() {
478e0d4afb2d4caecb264852a35f6e3cfc1248e08c4Wei Wang                    mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult);
4799fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang                }
4809fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            });
4819fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang        }
4829fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang
4839fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang        @Override
4849fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang        public void onBatchScanResults(final List<ScanResult> results) {
4859fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            Handler handler = new Handler(Looper.getMainLooper());
4869fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            handler.post(new Runnable() {
487b661bb79584f83ae95713e502fc14363c80c0278Wei Wang                @Override
4889fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang                public void run() {
4899fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang                    mScanCallback.onBatchScanResults(results);
4909fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang                }
4919fb1791e1a6859bfb14006a6d101cdecc88f3f95Wei Wang            });
4926d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        }
4936d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
4946d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        @Override
495d5324e4183c97ae7271b6eda4204d9f0dc003023Prerepa Viswanadham        public void onFoundOrLost(final boolean onFound, final ScanResult scanResult) {
496020bd7b861dfd560fad9f761f2778ebbac8be20eWei Wang            if (VDBG) {
497d5324e4183c97ae7271b6eda4204d9f0dc003023Prerepa Viswanadham                Log.d(TAG, "onFoundOrLost() - onFound = " + onFound +
498d5324e4183c97ae7271b6eda4204d9f0dc003023Prerepa Viswanadham                        " " + scanResult.toString());
4998f2e74cac282afa0bcf98f5d7131268147d12efePrerepa Viswanadham            }
500d5324e4183c97ae7271b6eda4204d9f0dc003023Prerepa Viswanadham
501d5324e4183c97ae7271b6eda4204d9f0dc003023Prerepa Viswanadham            // Check null in case the scan has been stopped
502d5324e4183c97ae7271b6eda4204d9f0dc003023Prerepa Viswanadham            synchronized (this) {
5031b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                if (mScannerId <= 0)
5040d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang                    return;
5058f2e74cac282afa0bcf98f5d7131268147d12efePrerepa Viswanadham            }
506d5324e4183c97ae7271b6eda4204d9f0dc003023Prerepa Viswanadham            Handler handler = new Handler(Looper.getMainLooper());
507d5324e4183c97ae7271b6eda4204d9f0dc003023Prerepa Viswanadham            handler.post(new Runnable() {
508d5324e4183c97ae7271b6eda4204d9f0dc003023Prerepa Viswanadham                    @Override
509d5324e4183c97ae7271b6eda4204d9f0dc003023Prerepa Viswanadham                public void run() {
510d5324e4183c97ae7271b6eda4204d9f0dc003023Prerepa Viswanadham                    if (onFound) {
5110d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang                        mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_FIRST_MATCH,
5120d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang                                scanResult);
513d5324e4183c97ae7271b6eda4204d9f0dc003023Prerepa Viswanadham                    } else {
5140d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang                        mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_MATCH_LOST,
5150d0df3ce258f569c76dc7c4b5250c4e50029d6e6Wei Wang                                scanResult);
516d5324e4183c97ae7271b6eda4204d9f0dc003023Prerepa Viswanadham                    }
517d5324e4183c97ae7271b6eda4204d9f0dc003023Prerepa Viswanadham                }
518d5324e4183c97ae7271b6eda4204d9f0dc003023Prerepa Viswanadham            });
5198f2e74cac282afa0bcf98f5d7131268147d12efePrerepa Viswanadham        }
520db1dbb889588505cd340e954acbde7ebf7c086d6Prerepa Viswanadham
521db1dbb889588505cd340e954acbde7ebf7c086d6Prerepa Viswanadham        @Override
522db1dbb889588505cd340e954acbde7ebf7c086d6Prerepa Viswanadham        public void onScanManagerErrorCallback(final int errorCode) {
523db1dbb889588505cd340e954acbde7ebf7c086d6Prerepa Viswanadham            if (VDBG) {
524db1dbb889588505cd340e954acbde7ebf7c086d6Prerepa Viswanadham                Log.d(TAG, "onScanManagerErrorCallback() - errorCode = " + errorCode);
525db1dbb889588505cd340e954acbde7ebf7c086d6Prerepa Viswanadham            }
526db1dbb889588505cd340e954acbde7ebf7c086d6Prerepa Viswanadham            synchronized (this) {
5271b49e6eb04f2eef4d8056e7447d8e0789c291847Jakub Pawlowski                if (mScannerId <= 0)
528db1dbb889588505cd340e954acbde7ebf7c086d6Prerepa Viswanadham                    return;
529db1dbb889588505cd340e954acbde7ebf7c086d6Prerepa Viswanadham            }
530db1dbb889588505cd340e954acbde7ebf7c086d6Prerepa Viswanadham            postCallbackError(mScanCallback, errorCode);
531db1dbb889588505cd340e954acbde7ebf7c086d6Prerepa Viswanadham        }
5326d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    }
5336d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
534461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani    private int postCallbackErrorOrReturn(final ScanCallback callback, final int errorCode) {
535461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani        if (callback == null) {
536461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani            return errorCode;
537461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani        } else {
538461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani            postCallbackError(callback, errorCode);
539461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani            return ScanCallback.NO_ERROR;
540461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani        }
541461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani    }
542461111bc3d9b53f745a9be686504aee161f36c28Amith Yamasani
5436d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private void postCallbackError(final ScanCallback callback, final int errorCode) {
5446d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        mHandler.post(new Runnable() {
545b661bb79584f83ae95713e502fc14363c80c0278Wei Wang            @Override
5466d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            public void run() {
5476d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                callback.onScanFailed(errorCode);
5486d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            }
5496d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        });
5506d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    }
5518e5270fdf5639461d67e9a898a85520abac6053dPrerepa Viswanadham
5528e5270fdf5639461d67e9a898a85520abac6053dPrerepa Viswanadham    private boolean isSettingsConfigAllowedForScan(ScanSettings settings) {
553685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang        if (mBluetoothAdapter.isOffloadedFilteringSupported()) {
554685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang            return true;
555685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang        }
556af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang        final int callbackType = settings.getCallbackType();
557685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang        // Only support regular scan if no offloaded filter support.
558685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang        if (callbackType == ScanSettings.CALLBACK_TYPE_ALL_MATCHES
559685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang                && settings.getReportDelayMillis() == 0) {
560685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang            return true;
561af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang        }
562685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang        return false;
5638e5270fdf5639461d67e9a898a85520abac6053dPrerepa Viswanadham    }
564e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham
565e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham    private boolean isSettingsAndFilterComboAllowed(ScanSettings settings,
566e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham                        List <ScanFilter> filterList) {
567e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham        final int callbackType = settings.getCallbackType();
568e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham        // If onlost/onfound is requested, a non-empty filter is expected
569ab5267a4033c47761aeabad34d4228e59e6a0b07tturney        if ((callbackType & (ScanSettings.CALLBACK_TYPE_FIRST_MATCH
570ab5267a4033c47761aeabad34d4228e59e6a0b07tturney                        | ScanSettings.CALLBACK_TYPE_MATCH_LOST)) != 0) {
571e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham            if (filterList == null) {
572e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham                return false;
573e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham            }
574e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham            for (ScanFilter filter : filterList) {
575e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham                if (filter.isAllFieldsEmpty()) {
576e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham                    return false;
577e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham                }
578e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham            }
579e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham        }
580e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham        return true;
581e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham    }
582e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham
583e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham    private boolean isHardwareResourcesAvailableForScan(ScanSettings settings) {
584e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham        final int callbackType = settings.getCallbackType();
585e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham        if ((callbackType & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0
586e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham                || (callbackType & ScanSettings.CALLBACK_TYPE_MATCH_LOST) != 0) {
587e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham            // For onlost/onfound, we required hw support be available
588e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham            return (mBluetoothAdapter.isOffloadedFilteringSupported() &&
589e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham                    mBluetoothAdapter.isHardwareTrackingFiltersAvailable());
590e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham        }
591e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham        return true;
592e593d0aec6430d98731d9751facd0414a1c9c6a2Prerepa Viswanadham    }
5936d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang}
594