package io.trygvis.android.bt; import android.app.Service; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothManager; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Handler; import android.os.IBinder; import android.util.Log; import android.widget.Toast; import java.util.ArrayList; import java.util.Collections; import java.util.List; import io.trygvis.soilmoisture.R; public class DefaultBtService extends Service implements BtService { private final static String TAG = DefaultBtService.class.getSimpleName(); private final IBinder binder = new LocalBinder<>(this); private Handler handler = new Handler(); // ----------------------------------------------------------------------- // State // ----------------------------------------------------------------------- private BtServiceListener serviceListener = new AbstractBtServiceListener() { @Override public void onNewDevice(BtDevice device) { } }; private Supplier tagConstructor; private BluetoothManager bluetoothManager; private BluetoothAdapter bluetoothAdapter; private final List> devices = new ArrayList<>(); private boolean scanning = false; // ----------------------------------------------------------------------- // BtService Implementation // ----------------------------------------------------------------------- @Override public boolean initialize(BtServiceListener serviceListener, Supplier dataSupplier) { if (bluetoothManager != null) { Log.e(TAG, "Already initialized"); return false; } this.tagConstructor = dataSupplier; if (serviceListener != null) { this.serviceListener = serviceListener; } // Use this check to determine whether BLE is supported on the device. Then you can // selectively disable BLE-related features. if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); return false; } // Initializes a Bluetooth adapter. For API level 18 and above, get a reference to // BluetoothAdapter through BluetoothManager. bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); if (bluetoothManager == null) { Log.e(TAG, "Unable to initialize BluetoothManager."); return false; } bluetoothAdapter = bluetoothManager.getAdapter(); if (bluetoothAdapter == null) { Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show(); bluetoothManager = null; return false; } Log.e(TAG, "Bluetooth initialized"); return true; } @Override public void clearCache() { } @Override public boolean isScanning() { return scanning; } @Override public boolean startScanning(long timeoutMs) { if (timeoutMs > 0) { handler.postDelayed(this::stopScanning, timeoutMs); } if (bluetoothAdapter.startLeScan(leScanCallback)) { scanning = true; serviceListener.onScanStarted(); return true; } return false; } @Override public void stopScanning() { // This doesn't mind being called twice. bluetoothAdapter.stopLeScan(leScanCallback); scanning = false; serviceListener.onScanStopped(); } // @Override public BtDevice getDevice(String mac) { BtDevice device = findDevice(mac); if (device != null) { return device; } BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(mac); return register(bluetoothDevice, null, null); } @Override public List> getDevices() { return Collections.unmodifiableList(devices); } // ----------------------------------------------------------------------- // Scanning // ----------------------------------------------------------------------- private BluetoothAdapter.LeScanCallback leScanCallback = (device, rssi, scanRecord) -> { // Log.i(TAG, "onLeScan()"); BtScanResult scanResult = new BtScanResult(scanRecord); register(device, rssi, scanResult); }; // ----------------------------------------------------------------------- // Service Implementation // ----------------------------------------------------------------------- @Override public IBinder onBind(Intent intent) { return binder; } // ----------------------------------------------------------------------- // Stuff // ----------------------------------------------------------------------- private BtDevice register(BluetoothDevice bluetoothDevice, Integer rssi, BtScanResult scanResult) { BtDevice btDevice = findDevice(bluetoothDevice.getAddress()); if (btDevice != null) { return btDevice; } Log.i(TAG, "New device: " + bluetoothDevice.getAddress()); btDevice = new BtDevice<>(this, bluetoothDevice, tagConstructor.get(), rssi, scanResult); devices.add(btDevice); serviceListener.onNewDevice(btDevice); return btDevice; } private BtDevice findDevice(String mac) { for (BtDevice d : devices) { if (d.getAddress().equals(mac)) { return d; } } return null; } }