The register() runnable can run after the activity has saved its state (e.g. app started in the background), in which case commitNow throws IllegalStateException and crashes the app. Rebuild Ble.jar.
300 lines
10 KiB
Java
300 lines
10 KiB
Java
package st.wow.git.ble;
|
|
|
|
import java.lang.String;
|
|
import java.lang.Runnable;
|
|
import java.util.List;
|
|
import java.util.UUID;
|
|
import android.app.Activity;
|
|
import android.app.Fragment;
|
|
import android.app.FragmentTransaction;
|
|
import android.bluetooth.BluetoothAdapter;
|
|
import android.bluetooth.BluetoothGatt;
|
|
import android.bluetooth.BluetoothGattCharacteristic;
|
|
import android.bluetooth.BluetoothGattDescriptor;
|
|
import android.bluetooth.BluetoothGattService;
|
|
import android.bluetooth.BluetoothManager;
|
|
import android.bluetooth.le.ScanResult;
|
|
import android.content.BroadcastReceiver;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.IntentFilter;
|
|
import android.content.pm.PackageManager;
|
|
import android.Manifest;
|
|
import android.os.Handler;
|
|
import android.util.Log;
|
|
import android.view.View;
|
|
|
|
import com.welie.blessed.BluetoothCentral;
|
|
import com.welie.blessed.BluetoothCentralCallback;
|
|
import com.welie.blessed.BluetoothPeripheral;
|
|
import com.welie.blessed.BluetoothPeripheralCallback;
|
|
|
|
public class BlessedConnect extends Fragment {
|
|
BluetoothCentral central;
|
|
boolean wantScan = false;
|
|
|
|
final int PERMISSION_REQUEST = 1;
|
|
final int REQUEST_ENABLE_BT = 2;
|
|
|
|
public BlessedConnect() {
|
|
Log.d("gio", "BlessedConnect()");
|
|
}
|
|
|
|
public void register(View view) {
|
|
Log.d("gio", "BlessedConnect: register()");
|
|
Context ctx = view.getContext();
|
|
Handler handler = new Handler(ctx.getMainLooper());
|
|
BlessedConnect inst = this;
|
|
handler.post(new Runnable() {
|
|
public void run() {
|
|
Activity act = (Activity)ctx;
|
|
FragmentTransaction ft = act.getFragmentManager().beginTransaction();
|
|
ft.add(inst, "BlessedConnect");
|
|
if (android.os.Build.VERSION.SDK_INT >= 24) {
|
|
ft.commitNowAllowingStateLoss();
|
|
} else {
|
|
ft.commitNow();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override public void onAttach(Context ctx) {
|
|
super.onAttach(ctx);
|
|
Log.d("gio", "BlessedConnect: onAttach()");
|
|
ctx.registerReceiver(receiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
|
|
if (ctx.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
|
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_REQUEST);
|
|
}
|
|
central = new BluetoothCentral(ctx, centralCallback, null);
|
|
System.loadLibrary("gio");
|
|
installComplete(this);
|
|
}
|
|
|
|
private final BroadcastReceiver receiver = new BroadcastReceiver() {
|
|
@Override
|
|
public void onReceive(Context context, Intent intent) {
|
|
Log.d("gio", "Received broadcast");
|
|
if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
|
|
updateState(intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1));
|
|
}
|
|
}
|
|
};
|
|
|
|
public boolean enabled() {
|
|
Context ctx = getContext();
|
|
//The Blessed library does not expose this functionality, so
|
|
//we need to get our own BluetoothAdapter and check its status.
|
|
BluetoothAdapter adapter = ((BluetoothManager)ctx.getSystemService(ctx.BLUETOOTH_SERVICE)).getAdapter();
|
|
return (adapter != null && adapter.isEnabled());
|
|
}
|
|
|
|
@Override
|
|
public void onDestroy() {
|
|
Log.d("gio","onDestroy()");
|
|
stopScan();
|
|
getContext().unregisterReceiver(receiver);
|
|
super.onDestroy();
|
|
}
|
|
|
|
public void scan() {
|
|
if (enabled()) {
|
|
central.scanForPeripherals();
|
|
} else {
|
|
wantScan = true;
|
|
}
|
|
}
|
|
|
|
public void stopScan() {
|
|
central.stopScan();
|
|
}
|
|
|
|
private final BluetoothCentralCallback centralCallback = new BluetoothCentralCallback() {
|
|
@Override
|
|
public void onDiscoveredPeripheral(BluetoothPeripheral peripheral, ScanResult scanResult) {
|
|
Log.d("gio", "BlessedConnect: onDiscoveredPeripheral(): " + peripheral.getName());
|
|
onScan(peripheral.getName(), peripheral.getAddress(), scanResult.getRssi(), peripheral);
|
|
}
|
|
|
|
@Override
|
|
public void onConnectedPeripheral(BluetoothPeripheral peripheral) {
|
|
if (peripheral.getState() == peripheral.STATE_CONNECTED) {
|
|
Log.d("gio", "BlessedConnect: Connected to " + peripheral.getName());
|
|
Log.d("gio", "BlessedConnect: Address = " + peripheral.getAddress());
|
|
|
|
onConnect(peripheral, peripheral.getAddress());
|
|
} else {
|
|
onDisconnect(peripheral, peripheral.getAddress());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onConnectionFailed(BluetoothPeripheral peripheral, int status) {
|
|
Log.d("gio", "BlessedConnect: onConnectionFailed()");
|
|
onDisconnect(peripheral, peripheral.getAddress());
|
|
}
|
|
|
|
@Override
|
|
public void onDisconnectedPeripheral(BluetoothPeripheral peripheral, int status) {
|
|
Log.d("gio", "BlessedConnect: Disconnected");
|
|
onDisconnect(peripheral, peripheral.getAddress());
|
|
}
|
|
|
|
@Override
|
|
public void onScanFailed(int errorCode) {
|
|
Log.d("gio", "BlessedConnect: Scan failed");
|
|
}
|
|
|
|
};
|
|
|
|
private final BluetoothPeripheralCallback peripheralCallback = new BluetoothPeripheralCallback() {
|
|
public void onBondingFailed(BluetoothPeripheral peripheral) {
|
|
Log.d("gio", "BlessedConnect: onBondingFailed()");
|
|
}
|
|
public void onBondingStarted(BluetoothPeripheral peripheral) {
|
|
Log.d("gio", "BlessedConnect: onBondingStarted()");
|
|
}
|
|
public void onBondingSucceeded(BluetoothPeripheral peripheral) {
|
|
Log.d("gio", "BlessedConnect: onBondingSucceeded()");
|
|
}
|
|
public void onBondLost(BluetoothPeripheral peripheral) {
|
|
Log.d("gio", "BlessedConnect: onBondLost()");
|
|
}
|
|
public void onCharacteristicUpdate(BluetoothPeripheral peripheral, byte[] value, BluetoothGattCharacteristic characteristic, int status) {
|
|
Log.d("gio", "BlessedConnect: onCharacteristicUpdate()");
|
|
characteristicChanged(peripheral.getAddress(), characteristic.getUuid().toString(), characteristic, value, value.length);
|
|
}
|
|
public void onCharacteristicWrite(BluetoothPeripheral peripheral, byte[] value, android.bluetooth.BluetoothGattCharacteristic characteristic, int status) {
|
|
Log.d("gio", "onCharacteristicWrite(): " + characteristic.getUuid().toString());
|
|
}
|
|
public void onDescriptorRead(BluetoothPeripheral peripheral, byte[] value, android.bluetooth.BluetoothGattDescriptor descriptor, int status) {
|
|
Log.d("gio", "onDescriptorRead()");
|
|
}
|
|
public void onDescriptorWrite(BluetoothPeripheral peripheral, byte[] value, android.bluetooth.BluetoothGattDescriptor descriptor, int status) {
|
|
Log.d("gio", "onDescriptorWrite(): " + descriptor.getUuid().toString());
|
|
}
|
|
public void onMtuChanged(BluetoothPeripheral peripheral, int mtu, int status) {
|
|
Log.d("gio", "onMtuChanged()");
|
|
}
|
|
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
|
|
Log.d("gio", "onReadRemoteRssi");
|
|
}
|
|
public void onNotificationStateUpdate(BluetoothPeripheral peripheral, BluetoothGattCharacteristic characteristic, int status) {
|
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
|
if(peripheral.isNotifying(characteristic)) {
|
|
Log.i("gio", String.format("BlessedConnect: Notify set to 'on' for %s", characteristic.getUuid()));
|
|
} else {
|
|
Log.i("gio", String.format("BlessedConnect: Notify set to 'off' for %s", characteristic.getUuid()));
|
|
}
|
|
} else {
|
|
Log.d("gio", "BlessedConnect: onNotificationStateUpdate(): failed");
|
|
}
|
|
}
|
|
public void onServicesDiscovered(BluetoothPeripheral peripheral) {
|
|
Log.d("gio", "BlessedConnect: onServicesDiscovered()");
|
|
}
|
|
};
|
|
|
|
public void connect(BluetoothPeripheral peripheral) {
|
|
if (peripheral == null) {
|
|
return;
|
|
}
|
|
Log.d("gio","BlessedConnect: connect");
|
|
central.connectPeripheral(peripheral, peripheralCallback);
|
|
}
|
|
|
|
public void disconnect(BluetoothPeripheral peripheral) {
|
|
if (peripheral == null) {
|
|
return;
|
|
}
|
|
Log.d("gio","BlessedConnect: disconnect");
|
|
peripheral.cancelConnection();
|
|
onDisconnect(peripheral, peripheral.getAddress());
|
|
}
|
|
|
|
public void discoverServices(BluetoothPeripheral peripheral) {
|
|
if (peripheral == null) {
|
|
return;
|
|
}
|
|
List<BluetoothGattService> services = peripheral.getServices();
|
|
for (BluetoothGattService serv : services) {
|
|
onDiscoverService(peripheral.getAddress(), serv.getUuid().toString(), serv);
|
|
}
|
|
}
|
|
|
|
public void discoverCharacteristics(BluetoothPeripheral peripheral, BluetoothGattService serv) {
|
|
if (peripheral == null || serv == null) {
|
|
return;
|
|
}
|
|
List<BluetoothGattCharacteristic> chrs = serv.getCharacteristics();
|
|
for (BluetoothGattCharacteristic chr : chrs) {
|
|
onDiscoverCharacteristic(peripheral.getAddress(), serv.getUuid().toString(), serv, chr.getUuid().toString(), chr);
|
|
}
|
|
}
|
|
|
|
public void readCharacteristic(BluetoothPeripheral peripheral, BluetoothGattCharacteristic chr) {
|
|
if (peripheral == null || chr == null) {
|
|
return;
|
|
}
|
|
peripheral.readCharacteristic(chr);
|
|
}
|
|
public boolean setCharacteristicNotification(BluetoothPeripheral peripheral, BluetoothGattCharacteristic chr) {
|
|
if (peripheral == null || chr == null) {
|
|
return false;
|
|
}
|
|
return peripheral.setNotify(chr, true);
|
|
}
|
|
|
|
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
Log.d("gio", "BlessedConnect: onActivityResult()");
|
|
if (requestCode == REQUEST_ENABLE_BT) {
|
|
Log.d("gio", "BlessedConnect: onActivityResult() REQUEST_ENABLE_BT");
|
|
switch (resultCode) {
|
|
case Activity.RESULT_OK: {
|
|
Log.d("gio", "BlessedConnect: onActivityResult() -- OK");
|
|
if (wantScan) {
|
|
scan();
|
|
}
|
|
break;
|
|
}
|
|
case Activity.RESULT_CANCELED: {
|
|
Log.d("gio", "BlessedConnect: onActivityResult() -- Cancelled");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onRequestPermissionsResult (int requestCode, String[] permissions, int[] grantResults) {
|
|
Log.d("gio", "BlessedConnect: onRequestPermissionsResult");
|
|
if (requestCode == PERMISSION_REQUEST) {
|
|
boolean granted = true;
|
|
for (int x : grantResults) {
|
|
if (x == PackageManager.PERMISSION_DENIED) {
|
|
granted = false;
|
|
break;
|
|
}
|
|
}
|
|
if (!granted) {
|
|
Log.d("gio", "BlessedConnect: permissions not granted");
|
|
return;
|
|
}
|
|
Log.d("gio", "BlessedConnect: permissions granted");
|
|
if (wantScan) {
|
|
scan();
|
|
}
|
|
}
|
|
}
|
|
|
|
static private native void installComplete(BlessedConnect p);
|
|
|
|
static private native void updateState(int s);
|
|
static private native void onScan(String name, String id, int rssi, BluetoothPeripheral peripheral);
|
|
static private native void onConnect(BluetoothPeripheral peripheral, String id);
|
|
static private native void onDisconnect(BluetoothPeripheral peripheral, String id);
|
|
static private native void onDiscoverService(String id, String uuid, BluetoothGattService serv);
|
|
static private native void onDiscoverCharacteristic(String id, String suuid, BluetoothGattService serv, String cuuid, BluetoothGattCharacteristic chr);
|
|
static private native void characteristicChanged(String id, String cuuid, BluetoothGattCharacteristic chr, byte[] value, int length);
|
|
}
|