// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.espressif.provisioning.device_scanner; import android.Manifest; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothManager; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.ScanCallback; import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; import android.content.Context; import android.os.Handler; import android.text.TextUtils; import android.util.Log; import androidx.annotation.RequiresPermission; import com.espressif.provisioning.listeners.BleScanListener; import java.util.ArrayList; import java.util.List; /** * This class is used for BLE scan functionality. */ public class BleScanner { private static final String TAG = "ESP:" + BleScanner.class.getSimpleName(); private static final long SCAN_TIME_OUT = 6000; private Handler handler; private BleScanListener bleScanListener; private BluetoothAdapter bluetoothAdapter; private BluetoothLeScanner bluetoothLeScanner; private boolean isScanning = false; private String prefix; public BleScanner(Context context, BleScanListener bleScannerListener) { this.bleScanListener = bleScannerListener; handler = new Handler(); BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); bluetoothAdapter = bluetoothManager.getAdapter(); } public BleScanner(Context context, String prefix, BleScanListener bleScannerListener) { this(context, bleScannerListener); this.prefix = prefix; } /** * This method is used to start BLE scan. */ @RequiresPermission(allOf = {Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN}) public void startScan() { if (!bluetoothAdapter.isEnabled()) { bleScanListener.scanStartFailed(); return; } Log.d(TAG, "Starting BLE device scanning..."); bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner(); List<ScanFilter> filters = new ArrayList<>(); ScanSettings settings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_BALANCED) .build(); isScanning = true; bluetoothLeScanner.startScan(filters, settings, scanCallback); handler.postDelayed(stopScanTask, SCAN_TIME_OUT); } /** * This method is used to start BLE scan. */ @RequiresPermission(allOf = {Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.BLUETOOTH}) public void stopScan() { Log.d(TAG, "Stop BLE device scan"); handler.removeCallbacks(stopScanTask); if (bluetoothLeScanner != null && bluetoothAdapter != null && bluetoothAdapter.isEnabled()) { try { bluetoothLeScanner.stopScan(scanCallback); } catch (Exception e) { Log.e(TAG, e.toString()); e.printStackTrace(); } } isScanning = false; bleScanListener.scanCompleted(); } /** * This method is used to check currently scanning is going on or not. * * @return Returns tru if scanning is going on. */ public boolean isScanning() { return isScanning; } private Runnable stopScanTask = new Runnable() { @Override @RequiresPermission(allOf = {Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.BLUETOOTH}) public void run() { stopScan(); } }; /** * ScanCallback to get scanned Peripheral. */ private final ScanCallback scanCallback = new ScanCallback() { @Override @RequiresPermission(Manifest.permission.BLUETOOTH) public void onScanResult(int callbackType, ScanResult result) { String deviceName = result.getDevice().getName(); if (result.getDevice() != null && !TextUtils.isEmpty(deviceName)) { Log.d(TAG, "========== Device Found : " + deviceName); if (TextUtils.isEmpty(prefix)) { bleScanListener.onPeripheralFound(result.getDevice(), result); } else if (deviceName.startsWith(prefix)) { bleScanListener.onPeripheralFound(result.getDevice(), result); } } } @Override public void onBatchScanResults(List<ScanResult> results) { super.onBatchScanResults(results); Log.d(TAG, "onBatchScanResults()"); } @Override public void onScanFailed(int errorCode) { super.onScanFailed(errorCode); Log.e(TAG, "onScanFailed, errorCode:" + errorCode); bleScanListener.onFailure(new RuntimeException("BLE scanning failed with error code : " + errorCode)); } }; }