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;
}
}