package st.wow.git.ble; import java.lang.Runnable; import java.lang.String; import java.util.List; import java.util.UUID; import android.util.Log; import java.lang.Class; import java.lang.ClassLoader; import java.lang.reflect.Constructor; import android.app.Activity; import android.app.Fragment; import android.os.Handler; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothProfile; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.Manifest; public class BleConnect extends Fragment { BluetoothManager manager; BluetoothAdapter adapter; Handler handler; boolean wantScan = false; final int PERMISSION_REQUEST = 1; final int REQUEST_ENABLE_BT = 1; public BleConnect() { Log.d("gio", "BleConnect()"); } @Override public void onAttach(Context ctx) { super.onAttach(ctx); Log.d("gio", "BleConnect: onAttach()"); ctx.registerReceiver(receiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); manager = (BluetoothManager) ctx.getSystemService(ctx.BLUETOOTH_SERVICE); adapter = manager.getAdapter(); handler = new Handler(ctx.getMainLooper()); if (!enabled()) { Log.d("gio", "BleConnect: enabling adapter"); Intent enableBtIntent = new Intent(adapter.ACTION_REQUEST_ENABLE); handler.post(new Runnable() { public void run() { startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } }); } else { Log.d("gio", "BleConnect: adapter is enabled"); } if (ctx.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_REQUEST); } installComplete(this); } public boolean enabled() { return (adapter != null && adapter.isEnabled()); } 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)); } } }; @Override public void onDestroy() { Log.d("gio","onDestroy()"); stopScan(); getContext().unregisterReceiver(receiver); super.onDestroy(); } private final BluetoothAdapter.LeScanCallback scanCallback = new BluetoothAdapter.LeScanCallback() { public void onLeScan(final BluetoothDevice dev, int rssi, byte[] scanRecord) { Log.d("gio","onLeScan(): " + dev.getName()); onScan(dev.getName(), dev.getAddress(), rssi, dev); } }; public void scan() { if (!enabled() || getContext().checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { Log.d("gio","BleConnect: scan() not enabled or no permissions, wantScan = true"); wantScan = true; return; } Log.d("gio","BleConnect: scan() starting scan"); wantScan = false; handler.post(new Runnable() { public void run() { adapter.startLeScan(scanCallback); } }); } public void stopScan() { if (!enabled()) { return; } Log.d("gio", "Stop scan"); handler.post(new Runnable() { public void run() { adapter.stopLeScan(scanCallback); } }); } private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { BluetoothDevice device = gatt.getDevice(); String addr = device.getAddress(); if (status != BluetoothGatt.GATT_SUCCESS) { Log.d("gio", "onConnectionStateChange: error code " + status); onDisconnect(gatt, addr); Log.d("gio", "gatt.close()"); gatt.close(); return; } switch (newState) { case BluetoothProfile.STATE_CONNECTED: { Log.d("gio", "Connected"); Log.d("gio", "Address = " + addr); onConnect(gatt, addr); break; } case BluetoothProfile.STATE_CONNECTING: case BluetoothProfile.STATE_DISCONNECTING: { break; } case BluetoothProfile.STATE_DISCONNECTED: { Log.d("gio", "Disconnected"); onDisconnect(gatt, addr); Log.d("gio", "gatt.close()"); gatt.close(); break; } default: { Log.d("gio", "onConnectionStateChange: unknown state"); onDisconnect(gatt, addr); Log.d("gio", "gatt.close()"); gatt.close(); break; } } } public void onServicesDiscovered(BluetoothGatt gatt, int status) { for (BluetoothGattService serv : gatt.getServices()) { onDiscoverService(gatt.getDevice().getAddress(), serv.getUuid().toString(), serv); } } public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic chr) { byte[] v = chr.getValue(); characteristicChanged(gatt.getDevice().getAddress(), chr.getUuid().toString(), chr, v, v.length); } }; public void connect(BluetoothDevice dev) { if (dev == null) { return; } Log.d("gio","BleConnect: connect"); handler.post(new Runnable() { public void run() { dev.connectGatt(getContext(), false, gattCallback, BluetoothDevice.TRANSPORT_LE); } }); } public void disconnect(BluetoothGatt gatt) { if (gatt == null) { return; } Log.d("gio","BleConnect: disconnect"); handler.post(new Runnable() { public void run() { boolean callClose = false; BluetoothDevice device = gatt.getDevice(); if (device != null) { callClose = (manager.getConnectionState(device, BluetoothProfile.GATT) != BluetoothGatt.STATE_CONNECTED); } gatt.disconnect(); if (callClose) { gatt.close(); } } }); } public void discoverServices(BluetoothGatt gatt) { if (gatt == null) { return; } handler.post(new Runnable() { public void run() { gatt.discoverServices(); } }); } public void discoverCharacteristics(BluetoothGatt gatt, BluetoothGattService serv) { Log.d("gio","BleConnect: discoverCharacteristics()"); if (gatt == null) { Log.d("gio","BleConnect: gatt == null"); return; } List chrs = serv.getCharacteristics(); if (chrs.isEmpty()) { Log.d("gio", "BleConnect: no characteristics found!"); } for (BluetoothGattCharacteristic chr : chrs) { Log.d("gio","BleConnect: -- " + chr.getUuid().toString()); onDiscoverCharacteristic(gatt.getDevice().getAddress(), serv.getUuid().toString(), serv, chr.getUuid().toString(), chr); } } public void setCharacteristicNotification(BluetoothGatt gatt, BluetoothGattCharacteristic chr) { gatt.setCharacteristicNotification(chr, true); BluetoothGattDescriptor descriptor = chr.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")); // Client Characteristic Config descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); gatt.writeDescriptor(descriptor); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { Log.d("gio", "BleConnect: onActivityResult()"); if (requestCode == REQUEST_ENABLE_BT) { Log.d("gio", "BleConnect: onActivityResult() REQUEST_ENABLE_BT"); switch (resultCode) { case Activity.RESULT_OK: { Log.d("gio", "BleConnect: onActivityResult() -- OK"); if (wantScan) { scan(); } break; } case Activity.RESULT_CANCELED: { Log.d("gio", "BleConnect: onActivityResult() -- Cancelled"); break; } } } } @Override public void onRequestPermissionsResult (int requestCode, String[] permissions, int[] grantResults) { Log.d("gio", "BleConnect: 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", "BleConnect: permissions not granted"); return; } Log.d("gio", "BleConnect: permissions granted"); if (wantScan) { scan(); } } } static private native void installComplete(BleConnect p); static private native void updateState(int s); static private native void onScan(String name, String id, int rssi, BluetoothDevice dev); static private native void onConnect(BluetoothGatt gatt, String id); static private native void onDisconnect(BluetoothGatt gatt, 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); }