Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2014 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| 5 | * use this file except in compliance with the License. You may obtain a copy of |
| 6 | * 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, WITHOUT |
| 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 13 | * License for the specific language governing permissions and limitations under |
| 14 | * the License. |
| 15 | */ |
| 16 | |
| 17 | package android.bluetooth.le; |
| 18 | |
Tor Norbye | 2d49752 | 2015-04-23 17:10:21 -0700 | [diff] [blame] | 19 | import android.Manifest; |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 20 | import android.annotation.NonNull; |
| 21 | import android.annotation.Nullable; |
Tor Norbye | 2d49752 | 2015-04-23 17:10:21 -0700 | [diff] [blame] | 22 | import android.annotation.RequiresPermission; |
Wei Wang | 0d0df3c | 2014-07-30 15:19:08 -0700 | [diff] [blame] | 23 | import android.annotation.SystemApi; |
Fyodor Kupolov | a179030 | 2015-06-19 15:35:11 -0700 | [diff] [blame] | 24 | import android.app.ActivityThread; |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 25 | import android.app.PendingIntent; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 26 | import android.bluetooth.BluetoothAdapter; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 27 | import android.bluetooth.BluetoothGatt; |
| 28 | import android.bluetooth.IBluetoothGatt; |
Wei Wang | 9fb1791 | 2014-07-01 15:10:06 -0700 | [diff] [blame] | 29 | import android.bluetooth.IBluetoothManager; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 30 | import android.os.Handler; |
| 31 | import android.os.Looper; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 32 | import android.os.RemoteException; |
Adam Lesinski | 6771d62 | 2016-01-15 18:14:47 -0800 | [diff] [blame] | 33 | import android.os.WorkSource; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 34 | import android.util.Log; |
| 35 | |
Wei Wang | 0d0df3c | 2014-07-30 15:19:08 -0700 | [diff] [blame] | 36 | import java.util.ArrayList; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 37 | import java.util.HashMap; |
| 38 | import java.util.List; |
| 39 | import java.util.Map; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 40 | |
| 41 | /** |
| 42 | * This class provides methods to perform scan related operations for Bluetooth LE devices. An |
Scott Kennedy | e7b0363 | 2015-04-10 10:25:34 -0700 | [diff] [blame] | 43 | * application can scan for a particular type of Bluetooth LE devices using {@link ScanFilter}. It |
Wei Wang | 685c1758 | 2014-07-16 22:02:03 -0700 | [diff] [blame] | 44 | * can also request different types of callbacks for delivering the result. |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 45 | * <p> |
| 46 | * Use {@link BluetoothAdapter#getBluetoothLeScanner()} to get an instance of |
| 47 | * {@link BluetoothLeScanner}. |
| 48 | * <p> |
Wei Wang | af74e66 | 2014-07-09 14:03:42 -0700 | [diff] [blame] | 49 | * <b>Note:</b> Most of the scan methods here require |
| 50 | * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 51 | * |
| 52 | * @see ScanFilter |
| 53 | */ |
| 54 | public final class BluetoothLeScanner { |
| 55 | |
| 56 | private static final String TAG = "BluetoothLeScanner"; |
| 57 | private static final boolean DBG = true; |
Wei Wang | 020bd7b | 2014-10-16 19:39:52 -0700 | [diff] [blame] | 58 | private static final boolean VDBG = false; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 59 | |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 60 | /** |
| 61 | * Extra containing a list of ScanResults. It can have one or more results if there was no |
| 62 | * error. In case of error, {@link #EXTRA_ERROR_CODE} will contain the error code and this |
| 63 | * extra will not be available. |
| 64 | */ |
Jack He | 2992cd0 | 2017-08-22 21:21:23 -0700 | [diff] [blame] | 65 | public static final String EXTRA_LIST_SCAN_RESULT = |
| 66 | "android.bluetooth.le.extra.LIST_SCAN_RESULT"; |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 67 | |
| 68 | /** |
| 69 | * Optional extra indicating the error code, if any. The error code will be one of the |
| 70 | * SCAN_FAILED_* codes in {@link ScanCallback}. |
| 71 | */ |
| 72 | public static final String EXTRA_ERROR_CODE = "android.bluetooth.le.extra.ERROR_CODE"; |
| 73 | |
| 74 | /** |
| 75 | * Optional extra indicating the callback type, which will be one of |
Amith Yamasani | ad8f086 | 2017-04-24 11:00:05 -0700 | [diff] [blame] | 76 | * CALLBACK_TYPE_* constants in {@link ScanSettings}. |
Jack He | a355e5e | 2017-08-22 16:06:54 -0700 | [diff] [blame] | 77 | * |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 78 | * @see ScanCallback#onScanResult(int, ScanResult) |
| 79 | */ |
| 80 | public static final String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE"; |
| 81 | |
Wei Wang | 9fb1791 | 2014-07-01 15:10:06 -0700 | [diff] [blame] | 82 | private final IBluetoothManager mBluetoothManager; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 83 | private final Handler mHandler; |
Prerepa Viswanadham | 8e5270f | 2014-07-08 16:33:34 -0700 | [diff] [blame] | 84 | private BluetoothAdapter mBluetoothAdapter; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 85 | private final Map<ScanCallback, BleScanCallbackWrapper> mLeScanClients; |
| 86 | |
| 87 | /** |
Wei Wang | af74e66 | 2014-07-09 14:03:42 -0700 | [diff] [blame] | 88 | * Use {@link BluetoothAdapter#getBluetoothLeScanner()} instead. |
Wei Wang | 685c1758 | 2014-07-16 22:02:03 -0700 | [diff] [blame] | 89 | * |
| 90 | * @param bluetoothManager BluetoothManager that conducts overall Bluetooth Management. |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 91 | * @hide |
| 92 | */ |
Wei Wang | 9fb1791 | 2014-07-01 15:10:06 -0700 | [diff] [blame] | 93 | public BluetoothLeScanner(IBluetoothManager bluetoothManager) { |
| 94 | mBluetoothManager = bluetoothManager; |
Prerepa Viswanadham | 8e5270f | 2014-07-08 16:33:34 -0700 | [diff] [blame] | 95 | mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 96 | mHandler = new Handler(Looper.getMainLooper()); |
| 97 | mLeScanClients = new HashMap<ScanCallback, BleScanCallbackWrapper>(); |
| 98 | } |
| 99 | |
| 100 | /** |
Wei Wang | 685c1758 | 2014-07-16 22:02:03 -0700 | [diff] [blame] | 101 | * Start Bluetooth LE scan with default parameters and no filters. The scan results will be |
Vinay Kalia | 875d27e | 2017-09-01 12:18:10 -0700 | [diff] [blame] | 102 | * delivered through {@code callback}. For unfiltered scans, scanning is stopped on screen |
| 103 | * off to save power. Scanning is resumed when screen is turned on again. To avoid this, use |
| 104 | * {@link #startScan(List, ScanSettings, ScanCallback)} with desired {@link ScanFilter}. |
Wei Wang | af74e66 | 2014-07-09 14:03:42 -0700 | [diff] [blame] | 105 | * <p> |
Fyodor Kupolov | 7bd8be0 | 2015-07-16 19:40:13 -0700 | [diff] [blame] | 106 | * An app must hold |
| 107 | * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or |
| 108 | * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission |
| 109 | * in order to get results. |
Wei Wang | af74e66 | 2014-07-09 14:03:42 -0700 | [diff] [blame] | 110 | * |
| 111 | * @param callback Callback used to deliver scan results. |
| 112 | * @throws IllegalArgumentException If {@code callback} is null. |
| 113 | */ |
Tor Norbye | 2d49752 | 2015-04-23 17:10:21 -0700 | [diff] [blame] | 114 | @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) |
Wei Wang | af74e66 | 2014-07-09 14:03:42 -0700 | [diff] [blame] | 115 | public void startScan(final ScanCallback callback) { |
Wei Wang | 833559d | 2014-08-29 10:26:13 -0700 | [diff] [blame] | 116 | startScan(null, new ScanSettings.Builder().build(), callback); |
Wei Wang | af74e66 | 2014-07-09 14:03:42 -0700 | [diff] [blame] | 117 | } |
| 118 | |
| 119 | /** |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 120 | * Start Bluetooth LE scan. The scan results will be delivered through {@code callback}. |
Vinay Kalia | 875d27e | 2017-09-01 12:18:10 -0700 | [diff] [blame] | 121 | * For unfiltered scans, scanning is stopped on screen off to save power. Scanning is |
| 122 | * resumed when screen is turned on again. To avoid this, do filetered scanning by |
| 123 | * using proper {@link ScanFilter}. |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 124 | * <p> |
Fyodor Kupolov | 7bd8be0 | 2015-07-16 19:40:13 -0700 | [diff] [blame] | 125 | * An app must hold |
| 126 | * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or |
| 127 | * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission |
| 128 | * in order to get results. |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 129 | * |
| 130 | * @param filters {@link ScanFilter}s for finding exact BLE devices. |
Wei Wang | af74e66 | 2014-07-09 14:03:42 -0700 | [diff] [blame] | 131 | * @param settings Settings for the scan. |
| 132 | * @param callback Callback used to deliver scan results. |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 133 | * @throws IllegalArgumentException If {@code settings} or {@code callback} is null. |
| 134 | */ |
Tor Norbye | 2d49752 | 2015-04-23 17:10:21 -0700 | [diff] [blame] | 135 | @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 136 | public void startScan(List<ScanFilter> filters, ScanSettings settings, |
| 137 | final ScanCallback callback) { |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 138 | startScan(filters, settings, null, callback, /*callbackIntent=*/ null, null); |
| 139 | } |
| 140 | |
| 141 | /** |
| 142 | * Start Bluetooth LE scan using a {@link PendingIntent}. The scan results will be delivered via |
| 143 | * the PendingIntent. Use this method of scanning if your process is not always running and it |
| 144 | * should be started when scan results are available. |
Amith Yamasani | 9622137 | 2017-06-21 14:06:44 -0700 | [diff] [blame] | 145 | * <p> |
Amith Yamasani | 172dd5c | 2017-09-05 13:41:19 -0700 | [diff] [blame] | 146 | * An app must hold |
| 147 | * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or |
| 148 | * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission |
| 149 | * in order to get results. |
| 150 | * <p> |
Amith Yamasani | 9622137 | 2017-06-21 14:06:44 -0700 | [diff] [blame] | 151 | * When the PendingIntent is delivered, the Intent passed to the receiver or activity |
| 152 | * will contain one or more of the extras {@link #EXTRA_CALLBACK_TYPE}, |
| 153 | * {@link #EXTRA_ERROR_CODE} and {@link #EXTRA_LIST_SCAN_RESULT} to indicate the result of |
| 154 | * the scan. |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 155 | * |
| 156 | * @param filters Optional list of ScanFilters for finding exact BLE devices. |
| 157 | * @param settings Optional settings for the scan. |
| 158 | * @param callbackIntent The PendingIntent to deliver the result to. |
| 159 | * @return Returns 0 for success or an error code from {@link ScanCallback} if the scan request |
| 160 | * could not be sent. |
| 161 | * @see #stopScan(PendingIntent) |
| 162 | */ |
| 163 | @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) |
| 164 | public int startScan(@Nullable List<ScanFilter> filters, @Nullable ScanSettings settings, |
| 165 | @NonNull PendingIntent callbackIntent) { |
| 166 | return startScan(filters, |
| 167 | settings != null ? settings : new ScanSettings.Builder().build(), |
| 168 | null, null, callbackIntent, null); |
Adam Lesinski | 6771d62 | 2016-01-15 18:14:47 -0800 | [diff] [blame] | 169 | } |
| 170 | |
| 171 | /** |
| 172 | * Start Bluetooth LE scan. Same as {@link #startScan(ScanCallback)} but allows the caller to |
| 173 | * specify on behalf of which application(s) the work is being done. |
| 174 | * |
| 175 | * @param workSource {@link WorkSource} identifying the application(s) for which to blame for |
Jack He | a355e5e | 2017-08-22 16:06:54 -0700 | [diff] [blame] | 176 | * the scan. |
Adam Lesinski | 6771d62 | 2016-01-15 18:14:47 -0800 | [diff] [blame] | 177 | * @param callback Callback used to deliver scan results. |
| 178 | * @hide |
| 179 | */ |
| 180 | @SystemApi |
| 181 | @RequiresPermission(allOf = { |
Jack He | a355e5e | 2017-08-22 16:06:54 -0700 | [diff] [blame] | 182 | Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.UPDATE_DEVICE_STATS}) |
Adam Lesinski | 6771d62 | 2016-01-15 18:14:47 -0800 | [diff] [blame] | 183 | public void startScanFromSource(final WorkSource workSource, final ScanCallback callback) { |
| 184 | startScanFromSource(null, new ScanSettings.Builder().build(), workSource, callback); |
| 185 | } |
| 186 | |
| 187 | /** |
| 188 | * Start Bluetooth LE scan. Same as {@link #startScan(List, ScanSettings, ScanCallback)} but |
| 189 | * allows the caller to specify on behalf of which application(s) the work is being done. |
| 190 | * |
| 191 | * @param filters {@link ScanFilter}s for finding exact BLE devices. |
| 192 | * @param settings Settings for the scan. |
| 193 | * @param workSource {@link WorkSource} identifying the application(s) for which to blame for |
Jack He | a355e5e | 2017-08-22 16:06:54 -0700 | [diff] [blame] | 194 | * the scan. |
Adam Lesinski | 6771d62 | 2016-01-15 18:14:47 -0800 | [diff] [blame] | 195 | * @param callback Callback used to deliver scan results. |
| 196 | * @hide |
| 197 | */ |
| 198 | @SystemApi |
| 199 | @RequiresPermission(allOf = { |
Jack He | a355e5e | 2017-08-22 16:06:54 -0700 | [diff] [blame] | 200 | Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.UPDATE_DEVICE_STATS}) |
Adam Lesinski | 6771d62 | 2016-01-15 18:14:47 -0800 | [diff] [blame] | 201 | public void startScanFromSource(List<ScanFilter> filters, ScanSettings settings, |
Jack He | a355e5e | 2017-08-22 16:06:54 -0700 | [diff] [blame] | 202 | final WorkSource workSource, final ScanCallback callback) { |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 203 | startScan(filters, settings, workSource, callback, null, null); |
Wei Wang | 0d0df3c | 2014-07-30 15:19:08 -0700 | [diff] [blame] | 204 | } |
| 205 | |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 206 | private int startScan(List<ScanFilter> filters, ScanSettings settings, |
Jack He | a355e5e | 2017-08-22 16:06:54 -0700 | [diff] [blame] | 207 | final WorkSource workSource, final ScanCallback callback, |
| 208 | final PendingIntent callbackIntent, |
| 209 | List<List<ResultStorageDescriptor>> resultStorages) { |
Wei Wang | 833559d | 2014-08-29 10:26:13 -0700 | [diff] [blame] | 210 | BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 211 | if (callback == null && callbackIntent == null) { |
Adam Lesinski | 6771d62 | 2016-01-15 18:14:47 -0800 | [diff] [blame] | 212 | throw new IllegalArgumentException("callback is null"); |
| 213 | } |
| 214 | if (settings == null) { |
| 215 | throw new IllegalArgumentException("settings is null"); |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 216 | } |
| 217 | synchronized (mLeScanClients) { |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 218 | if (callback != null && mLeScanClients.containsKey(callback)) { |
Vinay Kalia | 9722971 | 2017-07-28 15:09:57 -0700 | [diff] [blame] | 219 | return postCallbackErrorOrReturn(callback, |
| 220 | ScanCallback.SCAN_FAILED_ALREADY_STARTED); |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 221 | } |
Wei Wang | 9fb1791 | 2014-07-01 15:10:06 -0700 | [diff] [blame] | 222 | IBluetoothGatt gatt; |
| 223 | try { |
| 224 | gatt = mBluetoothManager.getBluetoothGatt(); |
| 225 | } catch (RemoteException e) { |
| 226 | gatt = null; |
| 227 | } |
| 228 | if (gatt == null) { |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 229 | return postCallbackErrorOrReturn(callback, ScanCallback.SCAN_FAILED_INTERNAL_ERROR); |
Wei Wang | 9fb1791 | 2014-07-01 15:10:06 -0700 | [diff] [blame] | 230 | } |
Prerepa Viswanadham | 8e5270f | 2014-07-08 16:33:34 -0700 | [diff] [blame] | 231 | if (!isSettingsConfigAllowedForScan(settings)) { |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 232 | return postCallbackErrorOrReturn(callback, |
Jack He | a355e5e | 2017-08-22 16:06:54 -0700 | [diff] [blame] | 233 | ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED); |
Prerepa Viswanadham | 8e5270f | 2014-07-08 16:33:34 -0700 | [diff] [blame] | 234 | } |
Prerepa Viswanadham | e593d0a | 2015-04-07 14:36:53 -0700 | [diff] [blame] | 235 | if (!isHardwareResourcesAvailableForScan(settings)) { |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 236 | return postCallbackErrorOrReturn(callback, |
Jack He | a355e5e | 2017-08-22 16:06:54 -0700 | [diff] [blame] | 237 | ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES); |
Prerepa Viswanadham | e593d0a | 2015-04-07 14:36:53 -0700 | [diff] [blame] | 238 | } |
| 239 | if (!isSettingsAndFilterComboAllowed(settings, filters)) { |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 240 | return postCallbackErrorOrReturn(callback, |
Prerepa Viswanadham | e593d0a | 2015-04-07 14:36:53 -0700 | [diff] [blame] | 241 | ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED); |
Prerepa Viswanadham | e593d0a | 2015-04-07 14:36:53 -0700 | [diff] [blame] | 242 | } |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 243 | if (callback != null) { |
| 244 | BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters, |
| 245 | settings, workSource, callback, resultStorages); |
| 246 | wrapper.startRegistration(); |
| 247 | } else { |
| 248 | try { |
| 249 | gatt.startScanForIntent(callbackIntent, settings, filters, |
| 250 | ActivityThread.currentOpPackageName()); |
| 251 | } catch (RemoteException e) { |
| 252 | return ScanCallback.SCAN_FAILED_INTERNAL_ERROR; |
| 253 | } |
| 254 | } |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 255 | } |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 256 | return ScanCallback.NO_ERROR; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 257 | } |
| 258 | |
| 259 | /** |
| 260 | * Stops an ongoing Bluetooth LE scan. |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 261 | * |
| 262 | * @param callback |
| 263 | */ |
Tor Norbye | 2d49752 | 2015-04-23 17:10:21 -0700 | [diff] [blame] | 264 | @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 265 | public void stopScan(ScanCallback callback) { |
Wei Wang | 833559d | 2014-08-29 10:26:13 -0700 | [diff] [blame] | 266 | BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 267 | synchronized (mLeScanClients) { |
| 268 | BleScanCallbackWrapper wrapper = mLeScanClients.remove(callback); |
| 269 | if (wrapper == null) { |
Wei Wang | b661bb7 | 2014-08-18 16:08:00 -0700 | [diff] [blame] | 270 | if (DBG) Log.d(TAG, "could not find callback wrapper"); |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 271 | return; |
| 272 | } |
| 273 | wrapper.stopLeScan(); |
| 274 | } |
| 275 | } |
| 276 | |
| 277 | /** |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 278 | * Stops an ongoing Bluetooth LE scan started using a PendingIntent. |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 279 | * |
| 280 | * @param callbackIntent The PendingIntent that was used to start the scan. |
| 281 | * @see #startScan(List, ScanSettings, PendingIntent) |
| 282 | */ |
| 283 | @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) |
| 284 | public void stopScan(PendingIntent callbackIntent) { |
| 285 | BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); |
| 286 | IBluetoothGatt gatt; |
| 287 | try { |
| 288 | gatt = mBluetoothManager.getBluetoothGatt(); |
| 289 | gatt.stopScanForIntent(callbackIntent, ActivityThread.currentOpPackageName()); |
| 290 | } catch (RemoteException e) { |
| 291 | } |
| 292 | } |
| 293 | |
| 294 | /** |
Wei Wang | 9fb1791 | 2014-07-01 15:10:06 -0700 | [diff] [blame] | 295 | * Flush pending batch scan results stored in Bluetooth controller. This will return Bluetooth |
| 296 | * LE scan results batched on bluetooth controller. Returns immediately, batch scan results data |
| 297 | * will be delivered through the {@code callback}. |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 298 | * |
| 299 | * @param callback Callback of the Bluetooth LE Scan, it has to be the same instance as the one |
Jack He | a355e5e | 2017-08-22 16:06:54 -0700 | [diff] [blame] | 300 | * used to start scan. |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 301 | */ |
Wei Wang | 9fb1791 | 2014-07-01 15:10:06 -0700 | [diff] [blame] | 302 | public void flushPendingScanResults(ScanCallback callback) { |
Wei Wang | 833559d | 2014-08-29 10:26:13 -0700 | [diff] [blame] | 303 | BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); |
Wei Wang | 9fb1791 | 2014-07-01 15:10:06 -0700 | [diff] [blame] | 304 | if (callback == null) { |
| 305 | throw new IllegalArgumentException("callback cannot be null!"); |
| 306 | } |
| 307 | synchronized (mLeScanClients) { |
| 308 | BleScanCallbackWrapper wrapper = mLeScanClients.get(callback); |
| 309 | if (wrapper == null) { |
| 310 | return; |
| 311 | } |
| 312 | wrapper.flushPendingBatchResults(); |
| 313 | } |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 314 | } |
| 315 | |
| 316 | /** |
Wei Wang | 0d0df3c | 2014-07-30 15:19:08 -0700 | [diff] [blame] | 317 | * Start truncated scan. |
| 318 | * |
| 319 | * @hide |
| 320 | */ |
| 321 | @SystemApi |
| 322 | public void startTruncatedScan(List<TruncatedFilter> truncatedFilters, ScanSettings settings, |
| 323 | final ScanCallback callback) { |
| 324 | int filterSize = truncatedFilters.size(); |
| 325 | List<ScanFilter> scanFilters = new ArrayList<ScanFilter>(filterSize); |
| 326 | List<List<ResultStorageDescriptor>> scanStorages = |
| 327 | new ArrayList<List<ResultStorageDescriptor>>(filterSize); |
| 328 | for (TruncatedFilter filter : truncatedFilters) { |
| 329 | scanFilters.add(filter.getFilter()); |
| 330 | scanStorages.add(filter.getStorageDescriptors()); |
| 331 | } |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 332 | startScan(scanFilters, settings, null, callback, null, scanStorages); |
Wei Wang | 0d0df3c | 2014-07-30 15:19:08 -0700 | [diff] [blame] | 333 | } |
| 334 | |
| 335 | /** |
Wei Wang | ee80922 | 2014-08-12 22:16:32 -0700 | [diff] [blame] | 336 | * Cleans up scan clients. Should be called when bluetooth is down. |
| 337 | * |
| 338 | * @hide |
| 339 | */ |
| 340 | public void cleanup() { |
| 341 | mLeScanClients.clear(); |
| 342 | } |
| 343 | |
| 344 | /** |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 345 | * Bluetooth GATT interface callbacks |
| 346 | */ |
Jakub Pawlowski | 1b49e6e | 2016-10-26 13:05:30 -0700 | [diff] [blame] | 347 | private class BleScanCallbackWrapper extends IScannerCallback.Stub { |
Wei Wang | b661bb7 | 2014-08-18 16:08:00 -0700 | [diff] [blame] | 348 | private static final int REGISTRATION_CALLBACK_TIMEOUT_MILLIS = 2000; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 349 | |
| 350 | private final ScanCallback mScanCallback; |
| 351 | private final List<ScanFilter> mFilters; |
Adam Lesinski | 6771d62 | 2016-01-15 18:14:47 -0800 | [diff] [blame] | 352 | private final WorkSource mWorkSource; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 353 | private ScanSettings mSettings; |
| 354 | private IBluetoothGatt mBluetoothGatt; |
Wei Wang | 0d0df3c | 2014-07-30 15:19:08 -0700 | [diff] [blame] | 355 | private List<List<ResultStorageDescriptor>> mResultStorages; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 356 | |
| 357 | // mLeHandle 0: not registered |
Jakub Pawlowski | ee02e1c | 2017-08-28 04:12:49 -0700 | [diff] [blame] | 358 | // -2: registration failed because app is scanning to frequently |
Wei Wang | 02bc008 | 2015-11-09 19:45:53 -0800 | [diff] [blame] | 359 | // -1: scan stopped or registration failed |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 360 | // > 0: registered and scan started |
Jakub Pawlowski | 1b49e6e | 2016-10-26 13:05:30 -0700 | [diff] [blame] | 361 | private int mScannerId; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 362 | |
| 363 | public BleScanCallbackWrapper(IBluetoothGatt bluetoothGatt, |
| 364 | List<ScanFilter> filters, ScanSettings settings, |
Adam Lesinski | 6771d62 | 2016-01-15 18:14:47 -0800 | [diff] [blame] | 365 | WorkSource workSource, ScanCallback scanCallback, |
| 366 | List<List<ResultStorageDescriptor>> resultStorages) { |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 367 | mBluetoothGatt = bluetoothGatt; |
| 368 | mFilters = filters; |
| 369 | mSettings = settings; |
Adam Lesinski | 6771d62 | 2016-01-15 18:14:47 -0800 | [diff] [blame] | 370 | mWorkSource = workSource; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 371 | mScanCallback = scanCallback; |
Jakub Pawlowski | 1b49e6e | 2016-10-26 13:05:30 -0700 | [diff] [blame] | 372 | mScannerId = 0; |
Wei Wang | 0d0df3c | 2014-07-30 15:19:08 -0700 | [diff] [blame] | 373 | mResultStorages = resultStorages; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 374 | } |
| 375 | |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 376 | public void startRegistration() { |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 377 | synchronized (this) { |
Wei Wang | b661bb7 | 2014-08-18 16:08:00 -0700 | [diff] [blame] | 378 | // Scan stopped. |
Jakub Pawlowski | ee02e1c | 2017-08-28 04:12:49 -0700 | [diff] [blame] | 379 | if (mScannerId == -1 || mScannerId == -2) return; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 380 | try { |
Ajay Panicker | a71643e | 2017-05-02 16:28:03 -0700 | [diff] [blame] | 381 | mBluetoothGatt.registerScanner(this, mWorkSource); |
Wei Wang | b661bb7 | 2014-08-18 16:08:00 -0700 | [diff] [blame] | 382 | wait(REGISTRATION_CALLBACK_TIMEOUT_MILLIS); |
| 383 | } catch (InterruptedException | RemoteException e) { |
| 384 | Log.e(TAG, "application registeration exception", e); |
| 385 | postCallbackError(mScanCallback, ScanCallback.SCAN_FAILED_INTERNAL_ERROR); |
| 386 | } |
Jakub Pawlowski | 1b49e6e | 2016-10-26 13:05:30 -0700 | [diff] [blame] | 387 | if (mScannerId > 0) { |
Wei Wang | b661bb7 | 2014-08-18 16:08:00 -0700 | [diff] [blame] | 388 | mLeScanClients.put(mScanCallback, this); |
| 389 | } else { |
Narayan Kamath | 728c8a0 | 2017-12-28 15:48:07 +0000 | [diff] [blame] | 390 | // Registration timed out or got exception, reset RscannerId to -1 so no |
Wei Wang | 02bc008 | 2015-11-09 19:45:53 -0800 | [diff] [blame] | 391 | // subsequent operations can proceed. |
Jakub Pawlowski | 1b49e6e | 2016-10-26 13:05:30 -0700 | [diff] [blame] | 392 | if (mScannerId == 0) mScannerId = -1; |
Jakub Pawlowski | ee02e1c | 2017-08-28 04:12:49 -0700 | [diff] [blame] | 393 | |
| 394 | // If scanning too frequently, don't report anything to the app. |
| 395 | if (mScannerId == -2) return; |
| 396 | |
Wei Wang | b661bb7 | 2014-08-18 16:08:00 -0700 | [diff] [blame] | 397 | postCallbackError(mScanCallback, |
| 398 | ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED); |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 399 | } |
| 400 | } |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 401 | } |
| 402 | |
| 403 | public void stopLeScan() { |
| 404 | synchronized (this) { |
Jakub Pawlowski | 1b49e6e | 2016-10-26 13:05:30 -0700 | [diff] [blame] | 405 | if (mScannerId <= 0) { |
| 406 | Log.e(TAG, "Error state, mLeHandle: " + mScannerId); |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 407 | return; |
| 408 | } |
| 409 | try { |
Jakub Pawlowski | 1b49e6e | 2016-10-26 13:05:30 -0700 | [diff] [blame] | 410 | mBluetoothGatt.stopScan(mScannerId); |
| 411 | mBluetoothGatt.unregisterScanner(mScannerId); |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 412 | } catch (RemoteException e) { |
Wei Wang | 9fb1791 | 2014-07-01 15:10:06 -0700 | [diff] [blame] | 413 | Log.e(TAG, "Failed to stop scan and unregister", e); |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 414 | } |
Jakub Pawlowski | 1b49e6e | 2016-10-26 13:05:30 -0700 | [diff] [blame] | 415 | mScannerId = -1; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 416 | } |
| 417 | } |
| 418 | |
Wei Wang | 9fb1791 | 2014-07-01 15:10:06 -0700 | [diff] [blame] | 419 | void flushPendingBatchResults() { |
| 420 | synchronized (this) { |
Jakub Pawlowski | 1b49e6e | 2016-10-26 13:05:30 -0700 | [diff] [blame] | 421 | if (mScannerId <= 0) { |
| 422 | Log.e(TAG, "Error state, mLeHandle: " + mScannerId); |
Wei Wang | 9fb1791 | 2014-07-01 15:10:06 -0700 | [diff] [blame] | 423 | return; |
| 424 | } |
| 425 | try { |
Jakub Pawlowski | 1b49e6e | 2016-10-26 13:05:30 -0700 | [diff] [blame] | 426 | mBluetoothGatt.flushPendingBatchResults(mScannerId); |
Wei Wang | 9fb1791 | 2014-07-01 15:10:06 -0700 | [diff] [blame] | 427 | } catch (RemoteException e) { |
| 428 | Log.e(TAG, "Failed to get pending scan results", e); |
| 429 | } |
| 430 | } |
| 431 | } |
| 432 | |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 433 | /** |
| 434 | * Application interface registered - app is ready to go |
| 435 | */ |
| 436 | @Override |
Jakub Pawlowski | 1b49e6e | 2016-10-26 13:05:30 -0700 | [diff] [blame] | 437 | public void onScannerRegistered(int status, int scannerId) { |
Jack He | 2992cd0 | 2017-08-22 21:21:23 -0700 | [diff] [blame] | 438 | Log.d(TAG, "onScannerRegistered() - status=" + status |
| 439 | + " scannerId=" + scannerId + " mScannerId=" + mScannerId); |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 440 | synchronized (this) { |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 441 | if (status == BluetoothGatt.GATT_SUCCESS) { |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 442 | try { |
Jakub Pawlowski | 1b49e6e | 2016-10-26 13:05:30 -0700 | [diff] [blame] | 443 | if (mScannerId == -1) { |
Wei Wang | 02bc008 | 2015-11-09 19:45:53 -0800 | [diff] [blame] | 444 | // Registration succeeds after timeout, unregister client. |
Jakub Pawlowski | 1b49e6e | 2016-10-26 13:05:30 -0700 | [diff] [blame] | 445 | mBluetoothGatt.unregisterClient(scannerId); |
Wei Wang | 02bc008 | 2015-11-09 19:45:53 -0800 | [diff] [blame] | 446 | } else { |
Jakub Pawlowski | 1b49e6e | 2016-10-26 13:05:30 -0700 | [diff] [blame] | 447 | mScannerId = scannerId; |
| 448 | mBluetoothGatt.startScan(mScannerId, mSettings, mFilters, |
Ajay Panicker | a71643e | 2017-05-02 16:28:03 -0700 | [diff] [blame] | 449 | mResultStorages, |
Wei Wang | 02bc008 | 2015-11-09 19:45:53 -0800 | [diff] [blame] | 450 | ActivityThread.currentOpPackageName()); |
| 451 | } |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 452 | } catch (RemoteException e) { |
| 453 | Log.e(TAG, "fail to start le scan: " + e); |
Jakub Pawlowski | 1b49e6e | 2016-10-26 13:05:30 -0700 | [diff] [blame] | 454 | mScannerId = -1; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 455 | } |
Jakub Pawlowski | ee02e1c | 2017-08-28 04:12:49 -0700 | [diff] [blame] | 456 | } else if (status == ScanCallback.SCAN_FAILED_SCANNING_TOO_FREQUENTLY) { |
| 457 | // applicaiton was scanning too frequently |
| 458 | mScannerId = -2; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 459 | } else { |
| 460 | // registration failed |
Jakub Pawlowski | 1b49e6e | 2016-10-26 13:05:30 -0700 | [diff] [blame] | 461 | mScannerId = -1; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 462 | } |
| 463 | notifyAll(); |
| 464 | } |
| 465 | } |
| 466 | |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 467 | /** |
| 468 | * Callback reporting an LE scan result. |
| 469 | * |
| 470 | * @hide |
| 471 | */ |
| 472 | @Override |
Wei Wang | e0d4afb | 2014-07-29 21:34:25 -0700 | [diff] [blame] | 473 | public void onScanResult(final ScanResult scanResult) { |
Wei Wang | 020bd7b | 2014-10-16 19:39:52 -0700 | [diff] [blame] | 474 | if (VDBG) Log.d(TAG, "onScanResult() - " + scanResult.toString()); |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 475 | |
| 476 | // Check null in case the scan has been stopped |
| 477 | synchronized (this) { |
Jakub Pawlowski | 1b49e6e | 2016-10-26 13:05:30 -0700 | [diff] [blame] | 478 | if (mScannerId <= 0) return; |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 479 | } |
Wei Wang | 9fb1791 | 2014-07-01 15:10:06 -0700 | [diff] [blame] | 480 | Handler handler = new Handler(Looper.getMainLooper()); |
| 481 | handler.post(new Runnable() { |
Wei Wang | b661bb7 | 2014-08-18 16:08:00 -0700 | [diff] [blame] | 482 | @Override |
Wei Wang | 9fb1791 | 2014-07-01 15:10:06 -0700 | [diff] [blame] | 483 | public void run() { |
Wei Wang | e0d4afb | 2014-07-29 21:34:25 -0700 | [diff] [blame] | 484 | mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult); |
Wei Wang | 9fb1791 | 2014-07-01 15:10:06 -0700 | [diff] [blame] | 485 | } |
| 486 | }); |
Wei Wang | 9fb1791 | 2014-07-01 15:10:06 -0700 | [diff] [blame] | 487 | } |
| 488 | |
| 489 | @Override |
| 490 | public void onBatchScanResults(final List<ScanResult> results) { |
| 491 | Handler handler = new Handler(Looper.getMainLooper()); |
| 492 | handler.post(new Runnable() { |
Wei Wang | b661bb7 | 2014-08-18 16:08:00 -0700 | [diff] [blame] | 493 | @Override |
Wei Wang | 9fb1791 | 2014-07-01 15:10:06 -0700 | [diff] [blame] | 494 | public void run() { |
| 495 | mScanCallback.onBatchScanResults(results); |
| 496 | } |
| 497 | }); |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 498 | } |
| 499 | |
| 500 | @Override |
Prerepa Viswanadham | d5324e4 | 2014-08-07 09:44:20 -0700 | [diff] [blame] | 501 | public void onFoundOrLost(final boolean onFound, final ScanResult scanResult) { |
Wei Wang | 020bd7b | 2014-10-16 19:39:52 -0700 | [diff] [blame] | 502 | if (VDBG) { |
Jack He | 2992cd0 | 2017-08-22 21:21:23 -0700 | [diff] [blame] | 503 | Log.d(TAG, "onFoundOrLost() - onFound = " + onFound + " " + scanResult.toString()); |
Prerepa Viswanadham | 8f2e74c | 2014-07-09 12:51:59 -0700 | [diff] [blame] | 504 | } |
Prerepa Viswanadham | d5324e4 | 2014-08-07 09:44:20 -0700 | [diff] [blame] | 505 | |
| 506 | // Check null in case the scan has been stopped |
| 507 | synchronized (this) { |
Jack He | a355e5e | 2017-08-22 16:06:54 -0700 | [diff] [blame] | 508 | if (mScannerId <= 0) { |
Wei Wang | 0d0df3c | 2014-07-30 15:19:08 -0700 | [diff] [blame] | 509 | return; |
Jack He | a355e5e | 2017-08-22 16:06:54 -0700 | [diff] [blame] | 510 | } |
Prerepa Viswanadham | 8f2e74c | 2014-07-09 12:51:59 -0700 | [diff] [blame] | 511 | } |
Prerepa Viswanadham | d5324e4 | 2014-08-07 09:44:20 -0700 | [diff] [blame] | 512 | Handler handler = new Handler(Looper.getMainLooper()); |
| 513 | handler.post(new Runnable() { |
Jack He | a355e5e | 2017-08-22 16:06:54 -0700 | [diff] [blame] | 514 | @Override |
Prerepa Viswanadham | d5324e4 | 2014-08-07 09:44:20 -0700 | [diff] [blame] | 515 | public void run() { |
| 516 | if (onFound) { |
Wei Wang | 0d0df3c | 2014-07-30 15:19:08 -0700 | [diff] [blame] | 517 | mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_FIRST_MATCH, |
| 518 | scanResult); |
Prerepa Viswanadham | d5324e4 | 2014-08-07 09:44:20 -0700 | [diff] [blame] | 519 | } else { |
Wei Wang | 0d0df3c | 2014-07-30 15:19:08 -0700 | [diff] [blame] | 520 | mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_MATCH_LOST, |
| 521 | scanResult); |
Prerepa Viswanadham | d5324e4 | 2014-08-07 09:44:20 -0700 | [diff] [blame] | 522 | } |
| 523 | } |
| 524 | }); |
Prerepa Viswanadham | 8f2e74c | 2014-07-09 12:51:59 -0700 | [diff] [blame] | 525 | } |
Prerepa Viswanadham | db1dbb8 | 2015-04-09 17:14:50 -0700 | [diff] [blame] | 526 | |
| 527 | @Override |
| 528 | public void onScanManagerErrorCallback(final int errorCode) { |
| 529 | if (VDBG) { |
| 530 | Log.d(TAG, "onScanManagerErrorCallback() - errorCode = " + errorCode); |
| 531 | } |
| 532 | synchronized (this) { |
Jack He | a355e5e | 2017-08-22 16:06:54 -0700 | [diff] [blame] | 533 | if (mScannerId <= 0) { |
Prerepa Viswanadham | db1dbb8 | 2015-04-09 17:14:50 -0700 | [diff] [blame] | 534 | return; |
Jack He | a355e5e | 2017-08-22 16:06:54 -0700 | [diff] [blame] | 535 | } |
Prerepa Viswanadham | db1dbb8 | 2015-04-09 17:14:50 -0700 | [diff] [blame] | 536 | } |
| 537 | postCallbackError(mScanCallback, errorCode); |
| 538 | } |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 539 | } |
| 540 | |
Amith Yamasani | 461111b | 2017-04-13 17:46:53 -0700 | [diff] [blame] | 541 | private int postCallbackErrorOrReturn(final ScanCallback callback, final int errorCode) { |
| 542 | if (callback == null) { |
| 543 | return errorCode; |
| 544 | } else { |
| 545 | postCallbackError(callback, errorCode); |
| 546 | return ScanCallback.NO_ERROR; |
| 547 | } |
| 548 | } |
| 549 | |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 550 | private void postCallbackError(final ScanCallback callback, final int errorCode) { |
| 551 | mHandler.post(new Runnable() { |
Wei Wang | b661bb7 | 2014-08-18 16:08:00 -0700 | [diff] [blame] | 552 | @Override |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 553 | public void run() { |
| 554 | callback.onScanFailed(errorCode); |
| 555 | } |
| 556 | }); |
| 557 | } |
Prerepa Viswanadham | 8e5270f | 2014-07-08 16:33:34 -0700 | [diff] [blame] | 558 | |
| 559 | private boolean isSettingsConfigAllowedForScan(ScanSettings settings) { |
Wei Wang | 685c1758 | 2014-07-16 22:02:03 -0700 | [diff] [blame] | 560 | if (mBluetoothAdapter.isOffloadedFilteringSupported()) { |
| 561 | return true; |
Prerepa Viswanadham | 8e5270f | 2014-07-08 16:33:34 -0700 | [diff] [blame] | 562 | } |
Wei Wang | 685c1758 | 2014-07-16 22:02:03 -0700 | [diff] [blame] | 563 | final int callbackType = settings.getCallbackType(); |
| 564 | // Only support regular scan if no offloaded filter support. |
| 565 | if (callbackType == ScanSettings.CALLBACK_TYPE_ALL_MATCHES |
| 566 | && settings.getReportDelayMillis() == 0) { |
| 567 | return true; |
| 568 | } |
| 569 | return false; |
Prerepa Viswanadham | 8e5270f | 2014-07-08 16:33:34 -0700 | [diff] [blame] | 570 | } |
Prerepa Viswanadham | e593d0a | 2015-04-07 14:36:53 -0700 | [diff] [blame] | 571 | |
| 572 | private boolean isSettingsAndFilterComboAllowed(ScanSettings settings, |
Jack He | a355e5e | 2017-08-22 16:06:54 -0700 | [diff] [blame] | 573 | List<ScanFilter> filterList) { |
Prerepa Viswanadham | e593d0a | 2015-04-07 14:36:53 -0700 | [diff] [blame] | 574 | final int callbackType = settings.getCallbackType(); |
| 575 | // If onlost/onfound is requested, a non-empty filter is expected |
tturney | ab5267a | 2015-04-13 14:55:07 -0700 | [diff] [blame] | 576 | if ((callbackType & (ScanSettings.CALLBACK_TYPE_FIRST_MATCH |
Jack He | a355e5e | 2017-08-22 16:06:54 -0700 | [diff] [blame] | 577 | | ScanSettings.CALLBACK_TYPE_MATCH_LOST)) != 0) { |
Prerepa Viswanadham | e593d0a | 2015-04-07 14:36:53 -0700 | [diff] [blame] | 578 | if (filterList == null) { |
| 579 | return false; |
| 580 | } |
| 581 | for (ScanFilter filter : filterList) { |
| 582 | if (filter.isAllFieldsEmpty()) { |
| 583 | return false; |
| 584 | } |
| 585 | } |
| 586 | } |
| 587 | return true; |
| 588 | } |
| 589 | |
| 590 | private boolean isHardwareResourcesAvailableForScan(ScanSettings settings) { |
| 591 | final int callbackType = settings.getCallbackType(); |
| 592 | if ((callbackType & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0 |
| 593 | || (callbackType & ScanSettings.CALLBACK_TYPE_MATCH_LOST) != 0) { |
| 594 | // For onlost/onfound, we required hw support be available |
Jack He | 2992cd0 | 2017-08-22 21:21:23 -0700 | [diff] [blame] | 595 | return (mBluetoothAdapter.isOffloadedFilteringSupported() |
| 596 | && mBluetoothAdapter.isHardwareTrackingFiltersAvailable()); |
Prerepa Viswanadham | e593d0a | 2015-04-07 14:36:53 -0700 | [diff] [blame] | 597 | } |
| 598 | return true; |
| 599 | } |
Wei Wang | 6d81118 | 2014-05-22 12:10:25 -0700 | [diff] [blame] | 600 | } |