I am a student working with BLE, and I am not good at English, so please understand it with the help of Google Translator.
Since the BLE notification does not work during the work, it is difficult to attach the source, so please help.
boolean success4 = mBluetoothGatt.writeDescriptor(descriptor); is false but I don't know why.
// Debugging
private static final String TAG = "BleManager";
// Constants that indicate the current connection state
public static final int STATE_ERROR = -1;
public static final int STATE_NONE = 0; // Initialized
public static final int STATE_IDLE = 1; // Not connected
public static final int STATE_SCANNING = 2; // Scanning
public static final int STATE_CONNECTING = 13; // Connecting
public static final int STATE_CONNECTED = 16; // Connected
// Message types sent from the BluetoothManager to Handler
public static final int MESSAGE_STATE_CHANGE = 1;
public static final int MESSAGE_READ = 2;
public static final int MESSAGE_WRITE = 3;
public static final int MESSAGE_DEVICE_NAME = 4;
public static final int MESSAGE_TOAST = 5;
public static final long SCAN_PERIOD = 10000; // Stops scanning after a pre-defined scan period.
public static final long SCAN_INTERVAL = 5 * 60 * 1000;
// System, Management
private static Context mContext = null;
Handler mHandler;
private boolean connect = false;
// Bluetooth
private BluetoothAdapter mBluetoothAdapter;
private BluetoothManager mBluetoothManager;
private BluetoothGattCharacteristic mcharacteristic;
private ArrayList<BluetoothDevice> mDeviceList = new ArrayList<BluetoothDevice>();
private BluetoothDevice mDefaultDevice = null;
private BluetoothGatt mBluetoothGatt = null;
private ArrayList<BluetoothGattService> mGattServices
= new ArrayList<BluetoothGattService>();
private BluetoothGattService mDefaultService = null;
private ArrayList<BluetoothGattCharacteristic> mGattCharacteristics
= new ArrayList<BluetoothGattCharacteristic>();
private ArrayList<BluetoothGattCharacteristic> mWritableCharacteristics
= new ArrayList<BluetoothGattCharacteristic>();
private BluetoothGattCharacteristic mDefaultChar = null;
// Parameters
private int mState = -1;
private void BleManager() {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();
//mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
mContext = this;
if (mContext == null) {return;}
else
{
scanLeDevice(true);
}
}
public synchronized void finalize() {
// Make sure we're not doing discovery anymore
if (mBluetoothAdapter != null) {
mState = STATE_IDLE;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
disconnect();
}
mDefaultDevice = null;
mBluetoothGatt = null;
mDefaultService = null;
mGattServices.clear();
mGattCharacteristics.clear();
mWritableCharacteristics.clear();
if (mContext == null)
return;
// Don't forget this!!
// Unregister broadcast listeners
// mContext.unregisterReceiver(mReceiver);
}
/*****************************************************
* Private methods
******************************************************/
/**
* This method extracts UUIDs from advertised data
* Because Android native code has bugs in parsing 128bit UUID
* use this method instead.
*/
private void stopScanning() {
if (mState < STATE_CONNECTING) {
mState = STATE_IDLE;
}
scanLeDevice(false);
//mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
/**
* Check services and looking for writable characteristics
*/
private int checkGattServices(List<BluetoothGattService> gattServices) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.e("# BluetoothAdapter", " not initialized");
return -1;
}
for (BluetoothGattService gattService : gattServices) {
// Default service info
Log.e("# GATT Service:", " " + gattService.getUuid().toString());
// Remember service
mGattServices.add(gattService);
// Extract characteristics
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
// Remember characteristic
mGattCharacteristics.add(gattCharacteristic);
for (BluetoothGattDescriptor descriptor:gattCharacteristic.getDescriptors()){
Log.e("# GATT Char:", gattCharacteristic.getUuid().toString());
Log.e(TAG, "BluetoothGattDescriptor: " + descriptor.getUuid().toString());
}
boolean isWritable = isWritableCharacteristic(gattCharacteristic);
if (isWritable) {
mWritableCharacteristics.add(gattCharacteristic);
}
boolean isReadable = isReadableCharacteristic(gattCharacteristic);
if (isReadable) {
readCharacteristic(gattCharacteristic);
}
if (isNotificationCharacteristic(gattCharacteristic) && gattCharacteristic.getUuid().toString().equals("0000ffe1-0000-1000-8000-00805f9b34fb")) {
setCharacteristicNotification(gattCharacteristic, true);
if (gattCharacteristic.getUuid().toString().equals("0000ffe1-0000-1000-8000-00805f9b34fb")) {
Log.e("default", "##############################################");
mDefaultChar = gattCharacteristic;
Log.e("default", "////////////////////////////////////////////// " + mDefaultChar.getUuid().toString());
//break;
}
}
}
}
return mWritableCharacteristics.size();
}
private boolean isWritableCharacteristic(BluetoothGattCharacteristic chr) {
if (chr == null) return false;
final int charaProp = chr.getProperties();
if (((charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE) |
(charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE)) > 0) {
Log.e("# Found writable", " characteristic");
return true;
} else {
Log.e("# Not writable", " characteristic");
return false;
}
}
private boolean isReadableCharacteristic(BluetoothGattCharacteristic chr) {
if (chr == null) return false;
final int charaProp = chr.getProperties();
if ((charaProp & BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
Log.e("# Found readable", " characteristic");
return true;
} else {
Log.e("# Not readable", " characteristic");
return false;
}
}
private boolean isNotificationCharacteristic(BluetoothGattCharacteristic chr) {
if (chr == null) return false;
final int charaProp = chr.getProperties();
if ((charaProp & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
Log.e("# Found notification", " characteristic");
return true;
} else {
Log.e("# Not notification", " characteristic");
return false;
}
}
/**
* Request a read on a given {#code BluetoothGattCharacteristic}. The read result is reported
* asynchronously through the {#code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}
* callback.
*
* #param characteristic The characteristic to read from.
*/
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.e("# BluetoothAdapter", " not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
/**
* Enables or disables notification on a give characteristic.
*
* #param characteristic Characteristic to act on.
* #param enabled If true, enable notification. False otherwise.
*/
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.e("# BluetoothAdapter ", "not initialized");
return;
}
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
boolean success1 = mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
//00002902-0000-1000-8000-00805f9b34fb
//public static String CLIENT_CHARACTERISTIC_CONFIG = "0000ffe1-0000-1000-8000-00805f9b34fb";
Log.e("info1",characteristic.getUuid().toString() + " // " + characteristic.getValue() + " // " + enabled + " // " + success1);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
Log.e("info2",characteristic.getUuid().toString() + " // " + characteristic.getValue() + " // " + enabled);
boolean success3 = descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
boolean success2 = descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
Log.e("info3",characteristic.getUuid().toString() + " // " + characteristic.getValue() + " // " + enabled + " // " + success3 + " // " + success2);
//boolean success5 = mBluetoothGatt.writeCharacteristic(characteristic);
boolean success4 = mBluetoothGatt.writeDescriptor(descriptor);
Log.e("info4",descriptor.getCharacteristic() + " // " + descriptor.getValue() + " // " + descriptor.getPermissions() + " // " + descriptor.getUuid() + " // " + enabled + " // " + success4);
//mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
}
/*****************************************************
* Public methods
******************************************************/
public int getState() {
return mState;
}
private void scanLeDevice(final boolean enable) {
mHandler = new Handler();
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}, SCAN_PERIOD);
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if(device.getName() != null && device.getName().equals("AINTEL_MFD") && connect == false){
connect = true;
scanLeDevice(false);
Log.e("ScanDevice",device.getName() + " // " + device.getUuids() + " // " + device.getAddress() + " // " + rssi + " // " + scanRecord[0] + " // " + scanRecord[1]);
connectGatt(Vars.mContext,false, device);
}
}
});
}
};
public boolean scanLeDevice(final boolean enable, UUID[] uuid) {
boolean isScanStarted = false;
if (enable) {
if (mState == STATE_SCANNING)
return false;
if (mBluetoothAdapter.startLeScan(uuid, mLeScanCallback)) {
mState = STATE_SCANNING;
mDeviceList.clear();
// If you want to scan for only specific types of peripherals
// call below function instead
//startLeScan(UUID[], BluetoothAdapter.LeScanCallback);
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
stopScanning();
}
}, SCAN_PERIOD);
isScanStarted = true;
}
} else {
if (mState < STATE_CONNECTING) {
mState = STATE_IDLE;
}
stopScanning();
}
return isScanStarted;
}
public boolean connectGatt(Context c, boolean bAutoReconnect, BluetoothDevice device) {
if (c == null || device == null)
return false;
mGattServices.clear();
mGattCharacteristics.clear();
mWritableCharacteristics.clear();
mBluetoothGatt = device.connectGatt(c, bAutoReconnect, mGattCallback);
mDefaultDevice = device;
mState = STATE_CONNECTING;
return true;
}
public boolean connectGatt(Context c, boolean bAutoReconnect, String address) {
if (c == null || address == null)
return false;
if (mBluetoothGatt != null && mDefaultDevice != null
&& address.equals(mDefaultDevice.getAddress())) {
if (mBluetoothGatt.connect()) {
mState = STATE_CONNECTING;
return true;
}
}
BluetoothDevice device =
BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
if (device == null) {
Log.e("# Device not found. ", "Unable to connect.");
return false;
}
mGattServices.clear();
mGattCharacteristics.clear();
mWritableCharacteristics.clear();
mBluetoothGatt = device.connectGatt(c, bAutoReconnect, mGattCallback);
mDefaultDevice = device;
mState = STATE_CONNECTING;
return true;
}
/**
* Disconnects an existing connection or cancel a pending connection. The disconnection result
* is reported asynchronously through the
* {#code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.e("# BluetoothAdapter", " not initialized");
return;
}
mBluetoothGatt.disconnect();
}
public boolean write(BluetoothGattCharacteristic chr, byte[] data) {
if (mBluetoothGatt == null) {
Log.e(TAG, "# BluetoothGatt not initialized");
return false;
}
BluetoothGattCharacteristic writableChar = null;
if (chr == null) {
if (mDefaultChar == null) {
for (BluetoothGattCharacteristic bgc : mWritableCharacteristics) {
if (isWritableCharacteristic(bgc)) {
writableChar = bgc;
}
}
if (writableChar == null) {
Log.e(TAG, "# Write failed - No available characteristic");
return false;
}
} else {
if (isWritableCharacteristic(mDefaultChar)) {
Log.e("# Default", "is PROPERY_WRITE | PROPERTY_WRITE_NO_RESPONSE");
writableChar = mDefaultChar;
} else {
Log.e("# De ", "is not writable");
mDefaultChar = null;
return false;
}
}
} else {
if (isWritableCharacteristic(chr)) {
Log.e("# user ", "GattCharacteristic is PROPERY_WRITE | PROPERTY_WRITE_NO_RESPONSE");
writableChar = chr;
} else {
Log.e("# user ", "GattCharacteristic is not writable");
return false;
}
}
writableChar.setValue(data);
writableChar.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
mBluetoothGatt.writeCharacteristic(writableChar);
mDefaultChar = writableChar;
return true;
}
public void setWritableCharacteristic(BluetoothGattCharacteristic chr) {
mDefaultChar = chr;
}
public ArrayList<BluetoothGattService> getServices() {
return mGattServices;
}
public ArrayList<BluetoothGattCharacteristic> getCharacteristics() {
return mGattCharacteristics;
}
public ArrayList<BluetoothGattCharacteristic> getWritableCharacteristics() {
return mWritableCharacteristics;
}
/*****************************************************
* Handler, Listener, Timer, Sub classes
******************************************************/
// Various callback methods defined by the BLE API.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mState = STATE_CONNECTED;
Log.e(TAG, "# Connected to GATT server.");
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mState = STATE_IDLE;
Log.e(TAG, "# Disconnected from GATT server.");
mBluetoothGatt = null;
mGattServices.clear();
mDefaultService = null;
mGattCharacteristics.clear();
mWritableCharacteristics.clear();
mDefaultChar = null;
mDefaultDevice = null;
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG, "# New GATT service discovered.");
checkGattServices(gatt.getServices());
} else {
Log.e(TAG, "# onServicesDiscovered received: " + status);
}
}
#Override
// Result of a characteristic read operation
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
// We've received data from remote
Log.e(TAG, "# Read characteristic11111: " + String.format("%02X",characteristic.getValue()));
/*
* onCharacteristicChanged callback receives same message
*
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
//for(byte byteChar : data)
// stringBuilder.append(String.format("%02X ", byteChar));
stringBuilder.append(data);
Log.e(TAG, stringBuilder.toString());
mHandler.obtainMessage(MESSAGE_READ, new String(data)).sendToTarget();
}
if(mDefaultChar == null && isWritableCharacteristic(characteristic)) {
mDefaultChar = characteristic;
}
*/
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
// We've received data from remote
byte[] newValue = characteristic.getValue();
Log.e(TAG, "# onCharacteristicChanged: " + String.format("%02X",newValue));
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
//for(byte byteChar : data)
// stringBuilder.append(String.format("%02X ", byteChar));
stringBuilder.append(data);
Log.e(TAG, stringBuilder.toString());
}
if (mDefaultChar == null && isWritableCharacteristic(characteristic)) {
mDefaultChar = characteristic;
}
}
};
}
3 things:
First make sure you have permissions. Requires Manifest.permission.BLUETOOTH permission.
Make sure your service/characteristic is correct.
Override onDescriptorWrite and check what you have done with writeDescriptor from there. If there is a problem, the onDescriptorWrite will tell you.
Google docs about BLE are not that good. Therefore, this amazing article will help you solve any issue with BLE.
Related
So for some reason my background service crashes, and I don't know why.
So my service contains BLE, and I bind to the service from the MainActivity with:
public void startBluetoothService() {
// Start the BLE Service
Log.d(TAG, "Starting BLE Service");
Intent gattServiceIntent = new Intent(this, BLE_Service.class);
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
Log.d(TAG, "Bluetooth is Enabled");
}
This runs, but then I get the following error
10-09 12:51:31.104 14007-14081/com.example.wrd I/ProviderInstaller: Installed default security provider GmsCore_OpenSSL
10-09 12:51:31.114 14007-14007/com.example.wrd D/AndroidRuntime: Shutting down VM
10-09 12:51:31.114 14007-14007/com.example.wrd E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.wrd, PID: 14007
java.lang.RuntimeException: Unable to instantiate service com.example.wrd.ble.BLE_Service: java.lang.InstantiationException: java.lang.Class<com.example.wrd.ble.BLE_Service> has no zero argument constructor
at android.app.ActivityThread.handleCreateService(ActivityThread.java:3841)
at android.app.ActivityThread.access$2100(ActivityThread.java:229)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1909)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:7325)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
Caused by: java.lang.InstantiationException: java.lang.Class<com.example.wrd.ble.BLE_Service> has no zero argument constructor
at java.lang.Class.newInstance(Native Method)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:3838)
at android.app.ActivityThread.access$2100(ActivityThread.java:229)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1909)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:7325)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
My service looks like this:
public class BLE_Service extends Service {
private Home ma;
private boolean mscanning;
public boolean Read = false;
private Handler mHandler;
private long scanPeriod;
private int signalStrength;
//Intent string
private static String DeviceAddress;
private static final String TAG = "BLE_Service";
// Bluetooth objects that we need to interact with
private static BluetoothManager mBluetoothManager;
private static BluetoothAdapter mBluetoothAdapter;
private static BluetoothGatt mBluetoothGatt;
private static BluetoothDevice device;
private static BluetoothGattCharacteristic BLECharacterisitc;
private final static String BaseUuid = "00000000-0000-1000-8000-00805f9b34f";
private final static String CSUuid = "00002902-0000-1000-8000-00805f9b34fb";
private final static String UuidWrite = BaseUuid + "0";
private final static String UuidRead = BaseUuid + "1";
private final static String UuidRead2 = BaseUuid + "2";
private final static String state_RW = BaseUuid + "0";
private final static String treatmentSettings_RW = BaseUuid + "1";
private final static String adjustment_RW = BaseUuid + "2";
private final static String validation_R = BaseUuid + "3";
//Broadcasts
public final static String BROADCAST_ADDED = "added";
public final static String BROADCAST_ADDEDFrag = "added";
// Bluetooth characteristics that we need to read/write
private static BluetoothGattCharacteristic mCharacterisitc, mCharacterisitc2, mCharacterisitcWrite, mCharacterisitc_state_RW,
mCharacterisitc_treatmentSettings_RW, mCharacterisitc_adjustment_RW, mCharacterisitc_validation_R;
private static StringBuilder sb = new StringBuilder();
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public boolean connecting(String DeviceAddress) {
Log.d(TAG, "Connection State: connect");
device = mBluetoothAdapter.getRemoteDevice(DeviceAddress);
if (device == null) {
Log.d(TAG, "Connection State Device Not Available ");
return false;
} else {
Log.d(TAG, "Connection State Connecting...");
device.connectGatt(this, false, mGattCallback);
return true;
}
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public boolean disconnect() {
mBluetoothGatt.disconnect();
mBluetoothGatt.close();
return true;
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void checkConnectedDevices() {
if (mBluetoothGatt != null){
String DeviceString = mBluetoothGatt.getDevice().getAddress();
String NameString = mBluetoothGatt.getDevice().getName();
Log.d(TAG, "checkConnectedDevices: " + NameString);
//broadCastHEX(BROADCAST_ADDEDFrag, NameString+";"+DeviceString, "get_conn_BLE_return");
}else{
//broadCastHEX(BROADCAST_ADDEDFrag, null, "Connected_BLE_Devices_return");
}
}
public class LocalBinder extends Binder {
public BLE_Service getService() {
return BLE_Service.this;
}
}
private final IBinder mBinder = new LocalBinder();
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
super.onDestroy();
}
/**
* Initializes a reference to the local Bluetooth adapter.
*
* #return Return true if the initialization is successful.
*/
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public boolean initialize() {
Log.d(TAG, "mBluetoothManager: service");
// For API level 18 and above, get a reference to BluetoothAdapter through
// BluetoothManager.
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
Log.e(TAG, "Unable to initialize BluetoothManager.");
return false;
}
}
Log.d(TAG, "mBluetoothManager: initialize");
BluetoothManager bluetoothManager = (BluetoothManager) getBaseContext().getSystemService(Context.BLUETOOTH_SERVICE);
List<BluetoothDevice> devices = bluetoothManager.getConnectedDevices(BluetoothProfile.GATT);
Log.d(TAG, "mBluetoothManager: initialize device" + devices.toString());
for(BluetoothDevice device : devices) {
if(device.getType() == BluetoothDevice.DEVICE_TYPE_LE) {
Log.d(TAG, "mBluetoothManager: running loop" + device.getName() + "\n");
}else{
Log.d(TAG, "mBluetoothManager: nothing" + device.getName() + "\n");
}
}
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
return true;
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public BLE_Service(Home home, long scanPeriod, int signalStrength) {
ma = home;
mHandler = new Handler();
this.scanPeriod = scanPeriod;
this.signalStrength = signalStrength;
final BluetoothManager bluetoothManager =
(BluetoothManager) ma.getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
}
public boolean isScanning() {
return mscanning;
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void start() {
if (!Utils.checkBluetooth(mBluetoothAdapter)) {
Utils.requestUserBluetooth(ma);
ma.stopScan();
} else {
scanLeDevice(true);
}
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void stop() {
scanLeDevice(false);
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private void scanLeDevice(final boolean enable) {
if (enable && !mscanning) {
Utils.toast(ma.getApplication(), "Starting BLE Scan...");
mHandler.postDelayed(new Runnable() {
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
#Override
public void run() {
Utils.toast(ma.getApplicationContext(), "Stopping BLE scan...");
mscanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
ma.stopScan();
}
}, scanPeriod);
mscanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
}
}
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
#Override
public void onConnectionStateChange(final BluetoothGatt gatt, int status, int newState) {
Log.d(TAG, "Connection State Change: " + status + " -> " + connectionState(newState));
gatt.discoverServices();
if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
/*
* Once successfully connected, we must next discover all the services on the
* device before we can read and write their characteristics.
*/
mBluetoothGatt = gatt;
BluetoothDevice device = gatt.getDevice();
Log.d(TAG, "Connection State onConnectionStateChange: " + device);
} else if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_DISCONNECTED) {
/*
* If at any point we disconnect, send a message to clear the weather values
* out of the UI
*/
Log.d(TAG, "Connection State: 2");
} else if (status != BluetoothGatt.GATT_SUCCESS) {
/*
* If there is a failure at any stage, simply disconnect
*/
}
}
/**
* This is called when a service discovery has completed.
*
* It gets the characteristics we are interested in and then
* broadcasts an update to the main activity.
*
* #param gatt The GATT database object
* #param status Status of whether the write was successful.
*/
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
#Override
public void onServicesDiscovered(final BluetoothGatt gatt, int status) {//prøv med ekstra status på denne
if (status == BluetoothGatt.GATT_SUCCESS) {
BluetoothGattService mBluetoothGattService = gatt.getService(UUID.fromString(CSUuid));
if (mBluetoothGattService != null) {
Log.i(TAG, "Connection State: Service characteristic UUID found: " + mBluetoothGattService.getUuid().toString());
mCharacterisitc = mBluetoothGattService.getCharacteristic(UUID.fromString(UuidRead));
mCharacterisitc2 = mBluetoothGattService.getCharacteristic(UUID.fromString(UuidRead2));
mCharacterisitcWrite = mBluetoothGattService.getCharacteristic(UUID.fromString(UuidWrite));
//First activate buttons here....
Log.w(TAG, "Connection State 1: mCharacterisitc " + mCharacterisitc + " " + mCharacterisitc2);
Intent broadcastIntent = new Intent().putExtra("ConnState", true);
broadcastIntent.setAction(BLE_Service.BROADCAST_ADDED);
LocalBroadcastManager.getInstance(BLE_Service.this).sendBroadcast(broadcastIntent);
if(Read){
readCharacteristic(gatt, mCharacterisitc);
}
} else {
Log.i(TAG, "Connection State: Service characteristic not found for UUID: " + UuidRead);
}
}
}
private String connectionState(int status) {
switch (status) {
case BluetoothProfile.STATE_CONNECTED:
return "Connection State: Connected";
case BluetoothProfile.STATE_DISCONNECTED:
return "Connection State: Disconnected";
case BluetoothProfile.STATE_CONNECTING:
return "Connection State: Connecting";
case BluetoothProfile.STATE_DISCONNECTING:
return "Connection State: Disconnecting";
default:
return String.valueOf(status);
}
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(TAG, "Connection State: onCharacteristicRead");
Log.w(TAG, "Connection State: Read 1");
// Verify that the read was the LED state
String uuid = characteristic.getUuid().toString();
// In this case, the only read the app does is the LED state.
// If the application had additional characteristics to read we could
// use a switch statement here to operate on each one separately.
if (uuid.equalsIgnoreCase(UuidRead)) {
Log.w(TAG, "Connection State: Read 2");
final int Val = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
broadCast(BROADCAST_ADDEDFrag, Val, "read_Service");
Log.i(TAG, "Connection State: onCharacteristicRead: " + Val);
Log.d(TAG, "Connection State Read state: "+Read);
readCharacteristic(gatt, mCharacterisitc2);
}
if (uuid.equalsIgnoreCase(UuidRead2)) {
Log.w(TAG, "Connection State: Read 3");
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for (byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
String msg = "letter: " + new String(data) + "\nHEX: " + stringBuilder.toString();
Log.d(TAG, "Connection State: onCharacteristicRead2: 4 " + msg);
broadCastHEX(BROADCAST_ADDEDFrag, msg, "read_Service2");
}
Read = false; //Has to be set to false in the last read message..
Log.d(TAG, "Connection State Read state: "+Read);
}
}
}
};
/**
* Runs service discovery on the connected device.
*
* #return
*/
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void discoverServices() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.d(TAG, "Connection State BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.discoverServices();
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void Write(Integer integer) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.d(TAG, "Connection State BluetoothAdapter not initialized");
return;
}
Integer Val = integer;
byte[] byteVal;
byteVal = intToByteArray(Val);
mCharacterisitcWrite.setValue(byteVal);
Log.d(TAG, "Connection State write 1: " + byteVal);
mBluetoothGatt.writeCharacteristic(mCharacterisitcWrite);
}
public static byte[] intToByteArray(int a) {
byte[] ret = new byte[4];
ret[3] = (byte) (a & 0xFF);
ret[2] = (byte) ((a >> 8) & 0xFF);
ret[1] = (byte) ((a >> 16) & 0xFF);
ret[0] = (byte) ((a >> 24) & 0xFF);
return ret;
}
/**
* This method is used to read the state of the LED from the device
*/
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void readCharacteristic(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || gatt == null) {
Log.w(TAG, "Connection State: BluetoothAdapter not initialized 2");
return;
}
Log.w(TAG, "Connection State: BluetoothAdapter initialized");
gatt.readCharacteristic(characteristic);
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
final int new_rssi = rssi;
if (rssi > signalStrength && device.getName() != null) {
mHandler.post(new Runnable() {
#Override
public void run() {
try {
FragmentBLE.addDevice(device, new_rssi);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
};
public void broadCast(String broadcastTXT, Integer Val, String key) {
Log.d(TAG, "Connection State: -> broadCast: Service Broadcast");
Intent broadcastIntent = new Intent().putExtra(key, Val);
broadcastIntent.setAction(broadcastTXT);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcastIntent);
}
public void broadCastHEX(String broadcastTXT, String Val, String key) {
Log.d(TAG, "Connection State: -> broadCast: Service Broadcast");
Intent broadcastIntent = new Intent().putExtra(key, Val);
broadcastIntent.setAction(broadcastTXT);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcastIntent);
}
}
So what causes this error to occure?
looks like it's somthing to do with java.lang.RuntimeException: Unable to instantiate service com.example.wrd.ble.BLE_Service, and I've been serching on it, but can't seem to find anything that helps.
EDIT
So my filled contructer is done before my empty contructer is set. I bind in my onStart()
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
#Override
protected void onStart() {
super.onStart();
// Start the BLE Service
Log.d(TAG, "Starting BLE Service");
Intent gattServiceIntent = new Intent(this, BLE_Service.class);
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
Log.d(TAG, "Bluetooth is Enabled");
registerReceiver(mBTStateUpdateReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
}
And then in my oncreate I run the following
mBTLeScanner = new BLE_Service(this, 7500, -75);
but somehow BLE_Service(this, 7500, -75) is finished before onStart()
Create an empty constructor.
BLE_Service(){
}
I am building an app where I need BLE devices to connect with each other and send messages. My problem is when my android device connects to an iOS device, only the iOS devices receives the message that android is advertising. Android never recieves the message iOS is sending. After debugging and testing, I am certain this is a problem with android, not iOS because iOS devices send and receive messages between each other properly.
I am confused on what to fix with my android code in order to have it successfully receive messages from iOS.
public class mapActivity extends AppCompatActivity implements OnMapReadyCallback {
private final Set<Peer> nearbyPeers = new HashSet<>();
private static Map<String, String> times = new HashMap<>();
private int counter = 0;
private static final String TAG2 = "ClientActivity";
private static final int REQUEST_ENABLE_BT = 1;
private static final String docName = "docName";
private boolean mConnected;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothLeScanner mBluetoothLeScanner;
private ScanCallback mScanCallback;
private BluetoothGatt mGatt;
public String covtraceUUID = "A82AB3FC-1695-4F7A-40F0-FE094CC218F8";
public static final long SCAN_PERIOD = 5000;
private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
private BluetoothGattServer mGattServer;
private BluetoothGatt gatt;
private boolean mEchoInitialized;
private List<BluetoothDevice> mDevices;
private BluetoothManager mBluetoothManager;
private boolean mInitialized;
FirebaseFirestore db = FirebaseFirestore.getInstance();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLogHandler = new Handler(Looper.getMainLooper());
mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();
#SuppressLint("HardwareIds")
String deviceInfo = "Device Info"
+ "\nName: " + mBluetoothAdapter.getName()
+ "\nAddress: " + mBluetoothAdapter.getAddress();
mHandler = new Handler();
mDevices = new ArrayList<>();
//End of ServerActivity
startScan();
}
#Override
protected void onResume() {
super.onResume();
//ClientActivity
// Check low energy support
//ServerActivity
// Check if bluetooth is enabled
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
// Request user to enable it
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivity(enableBtIntent);
finish();
return;
}
// Check low energy support
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
// Get a newer device
System.out.println("No LE Support.");
finish();
return;
}
// Check advertising
if (!mBluetoothAdapter.isMultipleAdvertisementSupported()) {
// Unable to run the server on this device, get a better device
System.out.println("No Advertising Support.");
finish();
return;
}
mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
GattServerCallback gattServerCallback = new GattServerCallback();
//try {
if (gattServerCallback == null || this == null || mBluetoothManager == null) {
System.out.println("unable to print gatt server");
return;
}
mGattServer = mBluetoothManager.openGattServer(this, gattServerCallback);
//}
//catch (Exception e) {
//}
#SuppressLint("HardwareIds")
String deviceInfo = "Device Info" + "\nName: " + mBluetoothAdapter.getName() + "\nAddress: " + mBluetoothAdapter.getAddress();
setupServer();
startAdvertising();
//startScan();
}
#Override
protected void onPause() {
super.onPause();
stopAdvertising();
stopServer();
}
//ServerActivity Start Advertising
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void startAdvertising() {
if (mBluetoothLeAdvertiser == null) {
return;
}
AdvertiseSettings settings = new AdvertiseSettings.Builder().setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
.setConnectable(true)
.setTimeout(0)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_LOW)
.build();
ParcelUuid parcelUuid = ParcelUuid.fromString(covtraceUUID);
AdvertiseData data = new AdvertiseData.Builder().setIncludeDeviceName(false)
//.addServiceUuid(new ParcelUuid(serviceUUID));
.addServiceUuid(parcelUuid)
.addServiceData( parcelUuid, "d".getBytes(Charset.forName("UTF-8") ) )
.build();
mBluetoothLeAdvertiser.startAdvertising(settings, data, mAdvertiseCallback);
}
//ServerActivity stop advertising
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void stopAdvertising() {
if (mBluetoothLeAdvertiser != null) {
mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
}
}
private AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {
#Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
System.out.println("Peripheral advertising started.");
}
#Override
public void onStartFailure(int errorCode) {
System.out.println("Peripheral advertising failed: " + errorCode);
}
};
//ServerActivity log
public void log1(String msg) {
Log.d(TAG, msg);
}
public void addDevice(BluetoothDevice device) {
System.out.println("Device added: " + device.getAddress());
mHandler.post(() -> mDevices.add(device));
}
public void removeDevice(BluetoothDevice device) {
System.out.println("Device removed: " + device.getAddress());
mHandler.post(() -> {
mDevices.remove(device);
});
}
private static boolean uuidMatches(String uuidString, String... matches) {
for (String match : matches) {
if (uuidString.equalsIgnoreCase(match)) {
return true;
}
}
return false;
}
private static boolean matchesServiceUuidString(String serviceIdString) {
String covtraceUUID = "A82AB3FC-1695-4F7A-40F0-FE094CC218F8";
return uuidMatches(serviceIdString, covtraceUUID);
}
#Nullable
private static BluetoothGattService findService(List<BluetoothGattService> serviceList) {
for (BluetoothGattService service : serviceList) {
String serviceIdString = service.getUuid()
.toString();
if (matchesServiceUuidString(serviceIdString)) {
return service;
}
}
return null;
}
private static boolean characteristicMatches(BluetoothGattCharacteristic characteristic, String uuidString) {
if (characteristic == null) {
return false;
}
UUID uuid = characteristic.getUuid();
return uuidMatches(uuid.toString(), uuidString);
}
#Nullable
private static BluetoothGattCharacteristic findCharacteristic(BluetoothGatt bluetoothGatt, String uuidString) {
List<BluetoothGattService> serviceList = bluetoothGatt.getServices();
BluetoothGattService service = findService(serviceList);
if (service == null) {
System.out.println("our service is null!!!!!!!");
return null;
}
List<BluetoothGattCharacteristic> characteristicList = service.getCharacteristics();
for (BluetoothGattCharacteristic characteristic : characteristicList) {
if (characteristicMatches(characteristic, uuidString)) {
return characteristic;
}
}
return null;
}
public static byte[] bytesFromString(String string) {
byte[] stringBytes = new byte[0];
try {
stringBytes = string.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Failed to convert message string to byte array");
}
return stringBytes;
}
#Nullable
public static BluetoothGattCharacteristic findEchoCharacteristic(BluetoothGatt bluetoothGatt) {
String covtraceUUID = "A82AB3FC-1695-4F7A-40F0-FE094CC218F8";
return findCharacteristic(bluetoothGatt, covtraceUUID);
}
//ServerActivity send message
private void sendMessage() {
if (!mConnected || !mEchoInitialized) {
return;
}
BluetoothGattCharacteristic characteristic = findEchoCharacteristic(mGatt);
if (characteristic == null) {
logError("Unable to find echo characteristic.");
disconnectGattServer();
return;
}
String message = String.valueOf(P2PKit.getMyPeerId());
byte[] messageBytes = bytesFromString(message);
if (messageBytes.length == 0) {
logError("Unable to convert message to bytes");
return;
}
characteristic.setValue(messageBytes);
boolean success = mGatt.writeCharacteristic(characteristic);
if (success) {
log("Wrote: " + byteArrayInHexFormat(messageBytes));
} else {
logError("Failed to write data");
}
}
//ServerActivity characteristic changed
private class CharacteristicChanged extends BluetoothGattCallback {
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
byte[] messageBytes = characteristic.getValue();
String messageString = null;
try {
messageString = new String(messageBytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
Log.d(TAG, "Unable to convert message bytes to string");
}
Log.d(messageString, "Received message: ");
}
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status != BluetoothGatt.GATT_SUCCESS) {
return;
}
BluetoothGattService service = gatt.getService(UUID.fromString(covtraceUUID));
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(covtraceUUID));
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
mInitialized = gatt.setCharacteristicNotification(characteristic, true);
}
}
public static boolean requiresResponse(BluetoothGattCharacteristic characteristic) {
return (characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE;
}
public void sendResponse(BluetoothDevice device, int requestId, int status, int offset, byte[] value) {
mHandler.post(() -> mGattServer.sendResponse(device, requestId, status, 0, null));
}
public static byte[] reverse(byte[] value) {
int length = value.length;
byte[] reversed = new byte[length];
for (int i = 0; i < length; i++) {
reversed[i] = value[length - (i + 1)];
}
return reversed;
}
private static String byteToHex(byte b) {
char char1 = Character.forDigit((b & 0xF0) >> 4, 16);
char char2 = Character.forDigit((b & 0x0F), 16);
return String.format("0x%1$s%2$s", char1, char2);
}
public static String byteArrayInHexFormat(byte[] byteArray) {
if (byteArray == null) {
return null;
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("{ ");
for (int i = 0; i < byteArray.length; i++) {
if (i > 0) {
stringBuilder.append(", ");
}
String hexString = byteToHex(byteArray[i]);
stringBuilder.append(hexString);
}
stringBuilder.append(" }");
return stringBuilder.toString();
}
public static boolean requiresConfirmation(BluetoothGattCharacteristic characteristic) {
return (characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) == BluetoothGattCharacteristic.PROPERTY_INDICATE;
}
private void notifyCharacteristic(byte[] value, UUID uuid) {
mHandler.post(() -> {
BluetoothGattService service = mGattServer.getService(UUID.fromString(covtraceUUID));
BluetoothGattCharacteristic characteristic = service.getCharacteristic(uuid);
log("Notifying characteristic " + characteristic.getUuid().toString()
+ ", new value: " + byteArrayInHexFormat(value));
characteristic.setValue(value);
boolean confirm = requiresConfirmation(characteristic);
for(BluetoothDevice device : mDevices) {
mGattServer.notifyCharacteristicChanged(device, characteristic, confirm);
}
});
}
public void notifyCharacteristicEcho(byte[] value) {
notifyCharacteristic(value, UUID.fromString(covtraceUUID));
}
private void sendReverseMessage(byte[] message) {
mHandler.post(() -> {
// Reverse message to differentiate original message & response
byte[] response = reverse(message);
log("Sending: " + byteArrayInHexFormat(response));
notifyCharacteristicEcho(response);
});
}
//ServerActivity gattservercallback
private class GattServerCallback extends BluetoothGattServerCallback {
#Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
super.onConnectionStateChange(device, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
addDevice(device);
connectDevice(device);
System.out.println("preparing to send msg 1");
sendMessage();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
removeDevice(device);
}
}
// The Gatt will reject Characteristic Read requests that do not have the permission set,
// so there is no need to check inside the callback
#Override
public void onCharacteristicReadRequest(BluetoothDevice device,
int requestId,
int offset,
BluetoothGattCharacteristic characteristic) {
super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
log("onCharacteristicReadRequest "
+ characteristic.getUuid().toString());
if (requiresResponse(characteristic)) {
// Unknown read characteristic requiring response, send failure
sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE, 0, null);
}
System.out.println("preparing to send msg 2");
sendMessage();
// Not one of our characteristics or has NO_RESPONSE property set
}
#Override
public void onCharacteristicWriteRequest(BluetoothDevice device,
int requestId,
BluetoothGattCharacteristic characteristic,
boolean preparedWrite,
boolean responseNeeded,
int offset,
byte[] value) {
super.onCharacteristicWriteRequest(device,
requestId,
characteristic,
preparedWrite,
responseNeeded,
offset,
value);
if (UUID.fromString(covtraceUUID).equals(characteristic.getUuid())) {
sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);
sendReverseMessage(value);
}
System.out.println("preparing to send msg 3");
sendMessage();
}
}
//ServerActivity set up server
private void setupServer() {
BluetoothGattService service = new BluetoothGattService(UUID.fromString(covtraceUUID),
BluetoothGattService.SERVICE_TYPE_PRIMARY);
mGattServer.addService(service);
}
//ServerActivity stop server
private void stopServer() {
if (mGattServer != null) {
mGattServer.close();
}
}
public void log(String msg) {
Log.d(TAG, msg);
mLogHandler.post(() -> {
Log.i(msg, msg + "\n");
});
}
public void logError(String msg) {
log("Error: " + msg);
}
//ClientActivity Scanning
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void startScan() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!hasPermissions() || mScanning) {
return;
}
}
disconnectGattServer();
mScanResults = new HashMap<>();
mScanCallback = new BtleScanCallback(mScanResults);
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
// Note: Filtering does not work the same (or at all) on most devices. It also is unable to
// search for a mask or anything less than a full UUID.
// Unless the full UUID of the server is known, manual filtering may be necessary.
// For example, when looking for a brand of device that contains a char sequence in the UUID
ScanFilter scanFilter = new ScanFilter.Builder()
.setServiceUuid(ParcelUuid.fromString(covtraceUUID))
.build();
List<ScanFilter> filters = new ArrayList<>();
filters.add(scanFilter);
ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
.build();
mBluetoothLeScanner.startScan(filters, settings, mScanCallback);
mHandler = new Handler();
//mHandler.postDelayed(this::stopScan, SCAN_PERIOD);
mScanning = true;
System.out.println("Started scanning.");
}
#RequiresApi(api = Build.VERSION_CODES.M)
private boolean hasPermissions() {
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
requestBluetoothEnable();
return false;
}
return true;
}
private void requestBluetoothEnable() {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
log("Requested user enables Bluetooth. Try starting the scan again.");
}
private void connectDevice(BluetoothDevice device) {
log("Connecting to " + device.getAddress());
GattClientCallback gattClientCallback = new GattClientCallback();
mGatt = device.connectGatt(this, false, gattClientCallback);
}
//ClientActivity Stop scan
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void stopScan() {
if (mScanning && mBluetoothAdapter != null && mBluetoothAdapter.isEnabled() && mBluetoothLeScanner != null) {
mBluetoothLeScanner.stopScan(mScanCallback);
scanComplete();
}
mScanCallback = null;
mScanning = false;
mHandler = null;
System.out.println("Stopped scanning.");
}
//ClientActivity scan Complete
private void scanComplete() {
if (mScanResults.isEmpty()) {
return;
}
for (String deviceAddress : mScanResults.keySet()) {
BluetoothDevice device = mScanResults.get(deviceAddress);
GattServerViewModel viewModel = new GattServerViewModel(device);
}
}
//Client Activity set connected
public void setConnected(boolean connected) {
mConnected = connected;
}
public void initializeEcho() {
mEchoInitialized = true;
}
//ClientActivity disconnect Gatt server
public void disconnectGattServer() {
System.out.println("Closing Gatt connection");
mConnected = false;
mEchoInitialized = false;
if (mGatt != null) {
mGatt.disconnect();
mGatt.close();
}
}
private static boolean matchesCharacteristicUuidString(String characteristicIdString) {
String covtraceUUID = "A82AB3FC-1695-4F7A-40F0-FE094CC218F8";
return uuidMatches(characteristicIdString, covtraceUUID);
}
private static boolean isMatchingCharacteristic(BluetoothGattCharacteristic characteristic) {
if (characteristic == null) {
return false;
}
UUID uuid = characteristic.getUuid();
return matchesCharacteristicUuidString(uuid.toString());
}
public static List<BluetoothGattCharacteristic> findCharacteristics(BluetoothGatt bluetoothGatt) {
List<BluetoothGattCharacteristic> matchingCharacteristics = new ArrayList<>();
List<BluetoothGattService> serviceList = bluetoothGatt.getServices();
BluetoothGattService service = findService(serviceList);
if (service == null) {
System.out.println("cannot find charac");
return matchingCharacteristics;
}
List<BluetoothGattCharacteristic> characteristicList = service.getCharacteristics();
for (BluetoothGattCharacteristic characteristic : characteristicList) {
if (isMatchingCharacteristic(characteristic)) {
matchingCharacteristics.add(characteristic);
}
}
return matchingCharacteristics;
}
//Client Activity callback
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private class BtleScanCallback extends ScanCallback {
private Map<String, BluetoothDevice> mScanResults;
BtleScanCallback(Map<String, BluetoothDevice> scanResults) {
mScanResults = scanResults;
}
#Override
public void onScanResult(int callbackType, ScanResult result) {
addScanResult(result);
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult result : results) {
addScanResult(result);
}
}
#Override
public void onScanFailed(int errorCode) {
logError("BLE Scan Failed with code " + errorCode);
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void addScanResult(ScanResult result) {
BluetoothDevice device = result.getDevice();
String deviceAddress = device.getAddress();
mScanResults.put(deviceAddress, device);
}
}
#Nullable
public static String stringFromBytes(byte[] bytes) {
String byteString = null;
try {
byteString = new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Unable to convert message bytes to string");
}
return byteString;
}
public static boolean isEchoCharacteristic(BluetoothGattCharacteristic characteristic) {
String covtraceUUID = "A82AB3FC-1695-4F7A-40F0-FE094CC218F8";
return characteristicMatches(characteristic, covtraceUUID );
}
//Gatt Client Callback
private class GattClientCallback extends BluetoothGattCallback {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
System.out.println("onConnectionStateChange newState: " + newState);
if (status == BluetoothGatt.GATT_FAILURE) {
logError("Connection Gatt failure status " + status);
disconnectGattServer();
return;
} else if (status != BluetoothGatt.GATT_SUCCESS) {
// handle anything not SUCCESS as failure
logError("Connection not GATT sucess status " + status);
disconnectGattServer();
return;
}
if (newState == BluetoothProfile.STATE_CONNECTED) {
System.out.println("Connected to device " + gatt.getDevice().getAddress());
mConnected = true;
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
System.out.println("Disconnected from device");
disconnectGattServer();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status != BluetoothGatt.GATT_SUCCESS) {
log("Device service discovery unsuccessful, status " + status);
return;
}
List<BluetoothGattCharacteristic> matchingCharacteristics = findCharacteristics(gatt);
if (matchingCharacteristics.isEmpty()) {
logError("Unable to find characteristics.");
return;
}
log("Initializing: setting write type and enabling notification");
for (BluetoothGattCharacteristic characteristic : matchingCharacteristics) {
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
enableCharacteristicNotification(gatt, characteristic);
}
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
log("Characteristic written successfully");
} else {
logError("Characteristic write unsuccessful, status: " + status);
disconnectGattServer();
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
log("Characteristic read successfully");
readCharacteristic(characteristic);
} else {
logError("Characteristic read unsuccessful, status: " + status);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
log("Characteristic changed, " + characteristic.getUuid().toString());
readCharacteristic(characteristic);
}
private void enableCharacteristicNotification(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
boolean characteristicWriteSuccess = gatt.setCharacteristicNotification(characteristic, true);
if (characteristicWriteSuccess) {
log("Characteristic notification set successfully for " + characteristic.getUuid().toString());
if (isEchoCharacteristic(characteristic)) {
System.out.println("enters isechocharac... ab to init");
initializeEcho();
System.out.println("preparing to send msg 4");
sendMessage();
}
} else {
logError("Characteristic notification set failure for " + characteristic.getUuid().toString());
}
}
private void readCharacteristic(BluetoothGattCharacteristic characteristic) {
byte[] messageBytes = characteristic.getValue();
log("Read: " + byteArrayInHexFormat(messageBytes));
String message = stringFromBytes(messageBytes);
if (message == null) {
logError("Unable to convert bytes to string");
return;
}
log("Received message: " + message);
}
}
#Override
public void onStart() {
super.onStart();
}
I am trying to adapt code from Bluetooth BLE developer starter kit to my own app (i.e this exact same code is working well on the example app).
But, I can't connect to any device, because, when I am pressing the Connect button (method onConnect), bluetooth_le_adapter is null.
I think that the bluetooth_le_adapter is not well initialized, and so, is null at startup.
Do you have any idea on how to fix this problem ? Thanks
PeripheralControlActivity.java:
public class PeripheralControlActivity extends Activity {
public static final String EXTRA_NAME = "name";
public static final String EXTRA_ID = "id";
private String device_name;
private String device_address;
private Timer mTimer;
private boolean sound_alarm_on_disconnect = false;
private int alert_level;
private boolean back_requested = false;
private boolean share_with_server = false;
private Switch share_switch;
private BleAdapterService bluetooth_le_adapter;
private final ServiceConnection service_connection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
bluetooth_le_adapter = ((BleAdapterService.LocalBinder) service).getService();
bluetooth_le_adapter.setActivityHandler(message_handler);
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
bluetooth_le_adapter = null;
}
};
private Handler message_handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Bundle bundle;
String service_uuid = "";
String characteristic_uuid = "";
byte[] b = null;
switch (msg.what) {
case BleAdapterService.MESSAGE:
bundle = msg.getData();
String text = bundle.getString(BleAdapterService.PARCEL_TEXT);
showMsg(text);
break;
case BleAdapterService.GATT_CONNECTED:
((Button) PeripheralControlActivity.this
.findViewById(R.id.connectButton)).setEnabled(false);
((Button) PeripheralControlActivity.this.findViewById(R.id.noiseButton))
.setEnabled(true);
share_switch.setEnabled(true);
// we're connected
showMsg("CONNECTED");
/*AlarmManager am = AlarmManager.getInstance();
Log.d(Constants.TAG, "alarmIsSounding=" + am.alarmIsSounding());
if (am.alarmIsSounding()) {
Log.d(Constants.TAG, "Stopping alarm");
am.stopAlarm();
}*/
bluetooth_le_adapter.discoverServices();
break;
case BleAdapterService.GATT_DISCONNECT:
((Button) PeripheralControlActivity.this
.findViewById(R.id.connectButton)).setEnabled(true);
// we're disconnected
showMsg("DISCONNECTED");
// hide the rssi distance colored rectangle
((LinearLayout) PeripheralControlActivity.this
.findViewById(R.id.rectangle))
.setVisibility(View.INVISIBLE);
share_switch.setEnabled(false);
// disable the LOW/MID/HIGH alert level selection buttons
((Button) PeripheralControlActivity.this.findViewById(R.id.lowButton)).setEnabled(false);
((Button) PeripheralControlActivity.this.findViewById(R.id.midButton)).setEnabled(false);
((Button) PeripheralControlActivity.this.findViewById(R.id.highButton)).setEnabled(false);
// stop the rssi reading timer
stopTimer();
/*if (alert_level > 0) {
AlarmManager.getInstance().soundAlarm(getResources().openRawResourceFd(R.raw.alarm));
}*/
if (back_requested) {
PeripheralControlActivity.this.finish();
}
break;
case BleAdapterService.GATT_SERVICES_DISCOVERED:
// validate services and if ok....
List<BluetoothGattService> slist = bluetooth_le_adapter.getSupportedGattServices();
boolean link_loss_present = false;
boolean immediate_alert_present = false;
boolean tx_power_present = false;
boolean proximity_monitoring_present = false;
for (BluetoothGattService svc : slist) {
Log.d(Constants.TAG, "UUID=" + svc.getUuid().toString().toUpperCase() + " INSTANCE=" + svc.getInstanceId());
if (svc.getUuid().toString().equalsIgnoreCase(BleAdapterService.LINK_LOSS_SERVICE_UUID)) {
link_loss_present = true;
continue;
}
if (svc.getUuid().toString().equalsIgnoreCase(BleAdapterService.IMMEDIATE_ALERT_SERVICE_UUID)) {
immediate_alert_present = true;
continue;
}
if (svc.getUuid().toString().equalsIgnoreCase(BleAdapterService.TX_POWER_SERVICE_UUID)) {
tx_power_present = true;
continue;
}
if (svc.getUuid().toString().equalsIgnoreCase(BleAdapterService.PROXIMITY_MONITORING_SERVICE_UUID)) {
proximity_monitoring_present = true;
continue;
}
}
if (link_loss_present && immediate_alert_present && tx_power_present && proximity_monitoring_present) {
showMsg("Device has expected services");
// show the rssi distance colored rectangle
((LinearLayout) PeripheralControlActivity.this
.findViewById(R.id.rectangle))
.setVisibility(View.VISIBLE);
// enable the LOW/MID/HIGH alert level selection buttons
((Button) PeripheralControlActivity.this.findViewById(R.id.lowButton)).setEnabled(true);
((Button) PeripheralControlActivity.this.findViewById(R.id.midButton)).setEnabled(true);
((Button) PeripheralControlActivity.this.findViewById(R.id.highButton)).setEnabled(true);
showMsg("Reading alert_level");
bluetooth_le_adapter.readCharacteristic(
BleAdapterService.LINK_LOSS_SERVICE_UUID,
BleAdapterService.ALERT_LEVEL_CHARACTERISTIC);
} else {
showMsg("Device does not have expected GATT services");
}
break;
case BleAdapterService.GATT_REMOTE_RSSI:
bundle = msg.getData();
int rssi = bundle.getInt(BleAdapterService.PARCEL_RSSI);
PeripheralControlActivity.this.updateRssi(rssi);
break;
case BleAdapterService.GATT_CHARACTERISTIC_READ:
bundle = msg.getData();
Log.d(Constants.TAG, "Service=" + bundle.get(BleAdapterService.PARCEL_SERVICE_UUID).toString().toUpperCase() + " Characteristic=" + bundle.get(BleAdapterService.PARCEL_CHARACTERISTIC_UUID).toString().toUpperCase());
if (bundle.get(BleAdapterService.PARCEL_CHARACTERISTIC_UUID).toString().toUpperCase()
.equals(BleAdapterService.ALERT_LEVEL_CHARACTERISTIC)
&& bundle.get(BleAdapterService.PARCEL_SERVICE_UUID).toString().toUpperCase()
.equals(BleAdapterService.LINK_LOSS_SERVICE_UUID)) {
b = bundle.getByteArray(BleAdapterService.PARCEL_VALUE);
if (b.length > 0) {
PeripheralControlActivity.this.setAlertLevel((int) b[0]);
Log.d(Constants.TAG, "Current alert_level is set to: " + b[0]);
// show the rssi distance colored rectangle
((LinearLayout) PeripheralControlActivity.this
.findViewById(R.id.rectangle))
.setVisibility(View.VISIBLE);
// start off the rssi reading timer
startReadRssiTimer();
}
}
break;
case BleAdapterService.GATT_CHARACTERISTIC_WRITTEN:
bundle = msg.getData();
Log.d(Constants.TAG, "Service=" + bundle.get(BleAdapterService.PARCEL_SERVICE_UUID).toString().toUpperCase() + " Characteristic=" + bundle.get(BleAdapterService.PARCEL_CHARACTERISTIC_UUID).toString().toUpperCase());
if (bundle.get(BleAdapterService.PARCEL_CHARACTERISTIC_UUID).toString()
.toUpperCase().equals(BleAdapterService.ALERT_LEVEL_CHARACTERISTIC)
&& bundle.get(BleAdapterService.PARCEL_SERVICE_UUID).toString()
.toUpperCase().equals(BleAdapterService.LINK_LOSS_SERVICE_UUID)) {
b = bundle.getByteArray(BleAdapterService.PARCEL_VALUE);
Log.d(Constants.TAG, "New alert_level set to: " + b[0]);
PeripheralControlActivity.this.setAlertLevel((int) b[0]);
}
break;
}
}
};
public void onLow(View view) {
bluetooth_le_adapter.writeCharacteristic(BleAdapterService.LINK_LOSS_SERVICE_UUID, BleAdapterService.ALERT_LEVEL_CHARACTERISTIC, Constants.ALERT_LEVEL_LOW);
}
public void onMid(View view) {
bluetooth_le_adapter.writeCharacteristic(BleAdapterService.LINK_LOSS_SERVICE_UUID, BleAdapterService.ALERT_LEVEL_CHARACTERISTIC, Constants.ALERT_LEVEL_MID);
}
public void onHigh(View view) {
bluetooth_le_adapter.writeCharacteristic(BleAdapterService.LINK_LOSS_SERVICE_UUID, BleAdapterService.ALERT_LEVEL_CHARACTERISTIC, Constants.ALERT_LEVEL_HIGH);
}
public void onNoise(View view) {
byte[] al = new byte[1];
al[0] = (byte) alert_level;
bluetooth_le_adapter.writeCharacteristic(BleAdapterService.IMMEDIATE_ALERT_SERVICE_UUID, BleAdapterService.ALERT_LEVEL_CHARACTERISTIC, al);
}
public void onBackPressed() {
Log.d(Constants.TAG, "onBackPressed");
back_requested = true;
if (bluetooth_le_adapter.isConnected()) {
try {
bluetooth_le_adapter.disconnect();
} catch (Exception e) {
}
} else {
finish();
}
}
private void setAlertLevel(int alert_level) {
this.alert_level = alert_level;
((Button) this.findViewById(R.id.lowButton)).setTextColor(Color.parseColor("#000000"));
;
((Button) this.findViewById(R.id.midButton)).setTextColor(Color.parseColor("#000000"));
;
((Button) this.findViewById(R.id.highButton)).setTextColor(Color.parseColor("#000000"));
;
switch (alert_level) {
case 0:
((Button) this.findViewById(R.id.lowButton)).setTextColor(Color.parseColor("#FF0000"));
;
break;
case 1:
((Button) this.findViewById(R.id.midButton)).setTextColor(Color.parseColor("#FF0000"));
;
break;
case 2:
((Button) this.findViewById(R.id.highButton)).setTextColor(Color.parseColor("#FF0000"));
;
break;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_peripheral_control);
// read intent data
final Intent intent = getIntent();
device_name = intent.getStringExtra(EXTRA_NAME);
device_address = intent.getStringExtra(EXTRA_ID);
// show the device name
((TextView) this.findViewById(R.id.nameTextView)).setText("Device : " + device_name + " [" + device_address + "]");
// hide the coloured rectangle used to show green/amber/red rssi distance
((LinearLayout) this.findViewById(R.id.rectangle)).setVisibility(View.INVISIBLE);
// hide the coloured rectangle used to show green/amber/red rssi
// distance
((LinearLayout) this.findViewById(R.id.rectangle))
.setVisibility(View.INVISIBLE);
// disable the noise button
((Button) PeripheralControlActivity.this.findViewById(R.id.noiseButton))
.setEnabled(false);
// disable the LOW/MID/HIGH alert level selection buttons
((Button) this.findViewById(R.id.lowButton)).setEnabled(false);
((Button) this.findViewById(R.id.midButton)).setEnabled(false);
((Button) this.findViewById(R.id.highButton)).setEnabled(false);
share_switch = (Switch) this.findViewById(R.id.switch1);
share_switch.setEnabled(false);
share_switch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if (bluetooth_le_adapter != null) {
share_with_server = isChecked;
if (!isChecked && bluetooth_le_adapter.isConnected()) {
showMsg("Switched off sharing proximity data");
// write 0,0 to cause Arduino to switch off all LEDs
if (bluetooth_le_adapter.writeCharacteristic(
BleAdapterService.PROXIMITY_MONITORING_SERVICE_UUID,
BleAdapterService.CLIENT_PROXIMITY_CHARACTERISTIC,
new byte[]{0, 0})) {
} else {
showMsg("Failed to inform Arduino sharing has been disabled");
}
}
}
}
});
// connect to the Bluetooth adapter service
Intent gattServiceIntent = new Intent(this, BleAdapterService.class);
bindService(gattServiceIntent, service_connection, BIND_AUTO_CREATE);
showMsg("READY");
}
#Override
protected void onDestroy() {
super.onDestroy();
stopTimer();
unbindService(service_connection);
bluetooth_le_adapter = null;
}
private void showMsg(final String msg) {
Log.i(Constants.TAG, msg);
runOnUiThread(new Runnable() {
#Override
public void run() {
((TextView) findViewById(R.id.msgTextView)).setText(msg);
}
});
}
public void onConnect(View view) {
showMsg("onConnect");
if (bluetooth_le_adapter != null) {
if (bluetooth_le_adapter.connect(device_address)) {
((Button) PeripheralControlActivity.this
.findViewById(R.id.connectButton)).setEnabled(false);
} else {
showMsg("onConnect: failed to connect");
}
} else {
showMsg("onConnect: bluetooth_le_adapter=null");
}
}
private void startReadRssiTimer() {
mTimer = new Timer();
mTimer.schedule(new TimerTask() {
#Override
public void run() {
bluetooth_le_adapter.readRemoteRssi();
}
}, 0, 2000);
}
private void stopTimer() {
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
}
private void updateRssi(int rssi) {
((TextView) findViewById(R.id.rssiTextView)).setText("RSSI = "
+ Integer.toString(rssi));
LinearLayout layout = ((LinearLayout) PeripheralControlActivity.this
.findViewById(R.id.rectangle));
byte proximity_band = 3;
if (rssi < -80) {
layout.setBackgroundColor(0xFFFF0000);
} else if (rssi < -50) {
layout.setBackgroundColor(0xFFFF8A01);
proximity_band = 2;
} else {
layout.setBackgroundColor(0xFF00FF00);
proximity_band = 1;
}
layout.invalidate();
if (share_with_server) {
if (bluetooth_le_adapter.writeCharacteristic(
BleAdapterService.PROXIMITY_MONITORING_SERVICE_UUID,
BleAdapterService.CLIENT_PROXIMITY_CHARACTERISTIC,
new byte[]{proximity_band, (byte) rssi})) {
showMsg("proximity data shared: proximity_band:" + proximity_band + ",rssi:" + rssi);
} else {
showMsg("Failed to share proximity data");
}
}
}
}
BleAdapterService.java
public class BleAdapterService extends Service {
private BluetoothAdapter bluetooth_adapter;
private BluetoothGatt bluetooth_gatt;
private BluetoothManager bluetooth_manager;
private Handler activity_handler = null;
private BluetoothDevice device;
private BluetoothGattDescriptor descriptor;
private final IBinder binder = new LocalBinder();
public boolean isConnected() {
return connected;
}
private boolean connected = false;
// messages sent back to activity
public static final int GATT_CONNECTED = 1;
public static final int GATT_DISCONNECT = 2;
public static final int GATT_SERVICES_DISCOVERED = 3;
public static final int GATT_CHARACTERISTIC_READ = 4;
public static final int GATT_CHARACTERISTIC_WRITTEN = 5;
public static final int GATT_REMOTE_RSSI = 6;
public static final int MESSAGE = 7;
// message params
public static final String PARCEL_DESCRIPTOR_UUID = "DESCRIPTOR_UUID";
public static final String PARCEL_CHARACTERISTIC_UUID = "CHARACTERISTIC_UUID";
public static final String PARCEL_SERVICE_UUID = "SERVICE_UUID";
public static final String PARCEL_VALUE = "VALUE";
public static final String PARCEL_RSSI = "RSSI";
public static final String PARCEL_TEXT = "TEXT";
// service uuids
public static String IMMEDIATE_ALERT_SERVICE_UUID = "00001802-0000-1000-8000-00805F9B34FB";
public static String LINK_LOSS_SERVICE_UUID = "00001803-0000-1000-8000-00805F9B34FB";
public static String TX_POWER_SERVICE_UUID = "00001804-0000-1000-8000-00805F9B34FB";
public static String PROXIMITY_MONITORING_SERVICE_UUID = "3E099910-293F-11E4-93BD-AFD0FE6D1DFD";
// service characteristics
public static String ALERT_LEVEL_CHARACTERISTIC = "00002A06-0000-1000-8000-00805F9B34FB";
public static String CLIENT_PROXIMITY_CHARACTERISTIC = "3E099911-293F-11E4-93BD-AFD0FE6D1DFD";
public class LocalBinder extends Binder {
public BleAdapterService getService() {
return BleAdapterService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
// set activity the will receive the messages
public void setActivityHandler(Handler handler) {
activity_handler = handler;
}
private void sendConsoleMessage(String text) {
Message msg = Message.obtain(activity_handler, MESSAGE);
Bundle data = new Bundle();
data.putString(PARCEL_TEXT, text);
msg.setData(data);
msg.sendToTarget();
}
#Override
public void onCreate() {
if (bluetooth_manager == null) {
bluetooth_manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (bluetooth_manager == null) {
return;
}
}
bluetooth_adapter = bluetooth_manager.getAdapter();
if (bluetooth_adapter == null) {
return;
}
}
// connect to the device
public boolean connect(final String address) {
if (bluetooth_adapter == null || address == null) {
sendConsoleMessage("connect: bluetooth_adapter=null");
return false;
}
device = bluetooth_adapter.getRemoteDevice(address);
if (device == null) {
sendConsoleMessage("connect: device=null");
return false;
}
bluetooth_gatt = device.connectGatt(this, false, gatt_callback);
return true;
}
// disconnect from device
public void disconnect() {
sendConsoleMessage("disconnecting");
if (bluetooth_adapter == null || bluetooth_gatt == null) {
sendConsoleMessage("disconnect: bluetooth_adapter|bluetooth_gatt null");
return;
}
if (bluetooth_gatt != null) {
bluetooth_gatt.disconnect();
}
}
public void readRemoteRssi() {
if (bluetooth_adapter == null || bluetooth_gatt == null) {
return;
}
bluetooth_gatt.readRemoteRssi();
}
public void discoverServices() {
if (bluetooth_adapter == null || bluetooth_gatt == null) {
return;
}
Log.d(Constants.TAG,"Discovering GATT services");
bluetooth_gatt.discoverServices();
}
public List<BluetoothGattService> getSupportedGattServices() {
if (bluetooth_gatt == null)
return null;
return bluetooth_gatt.getServices();
}
public boolean readCharacteristic(String serviceUuid,
String characteristicUuid) {
Log.d(Constants.TAG,"readCharacteristic:"+characteristicUuid+" of " +serviceUuid);
if (bluetooth_adapter == null || bluetooth_gatt == null) {
sendConsoleMessage("readCharacteristic: bluetooth_adapter|bluetooth_gatt null");
return false;
}
BluetoothGattService gattService = bluetooth_gatt
.getService(java.util.UUID.fromString(serviceUuid));
if (gattService == null) {
sendConsoleMessage("readCharacteristic: gattService null");
return false;
}
BluetoothGattCharacteristic gattChar = gattService
.getCharacteristic(java.util.UUID.fromString(characteristicUuid));
if (gattChar == null) {
sendConsoleMessage("readCharacteristic: gattChar null");
return false;
}
return bluetooth_gatt.readCharacteristic(gattChar);
}
public boolean writeCharacteristic(String serviceUuid,
String characteristicUuid, byte[] value) {
Log.d(Constants.TAG,"writeCharacteristic:"+characteristicUuid+" of " +serviceUuid);
if (bluetooth_adapter == null || bluetooth_gatt == null) {
sendConsoleMessage("writeCharacteristic: bluetooth_adapter|bluetooth_gatt null");
return false;
}
BluetoothGattService gattService = bluetooth_gatt
.getService(java.util.UUID.fromString(serviceUuid));
if (gattService == null) {
sendConsoleMessage("writeCharacteristic: gattService null");
return false;
}
BluetoothGattCharacteristic gattChar = gattService
.getCharacteristic(java.util.UUID.fromString(characteristicUuid));
if (gattChar == null) {
sendConsoleMessage("writeCharacteristic: gattChar null");
return false;
}
gattChar.setValue(value);
return bluetooth_gatt.writeCharacteristic(gattChar);
}
private final BluetoothGattCallback gatt_callback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
Log.d(Constants.TAG, "onConnectionStateChange: status=" + status);
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.d(Constants.TAG, "onConnectionStateChange: CONNECTED");
connected = true;
Message msg = Message.obtain(activity_handler, GATT_CONNECTED);
msg.sendToTarget();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.d(Constants.TAG, "onConnectionStateChange: DISCONNECTED");
Message msg = Message.obtain(activity_handler, GATT_DISCONNECT);
msg.sendToTarget();
if (bluetooth_gatt != null) {
Log.d(Constants.TAG,"Closing and destroying BluetoothGatt object");
connected = false;
bluetooth_gatt.close();
bluetooth_gatt = null;
}
}
}
#Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
sendConsoleMessage("RSSI read OK");
Bundle bundle = new Bundle();
bundle.putInt(PARCEL_RSSI, rssi);
Message msg = Message
.obtain(activity_handler, GATT_REMOTE_RSSI);
msg.setData(bundle);
msg.sendToTarget();
} else {
sendConsoleMessage("RSSI read err:"+status);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
sendConsoleMessage("Services Discovered");
Message msg = Message.obtain(activity_handler,
GATT_SERVICES_DISCOVERED);
msg.sendToTarget();
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Bundle bundle = new Bundle();
bundle.putString(PARCEL_CHARACTERISTIC_UUID, characteristic.getUuid()
.toString());
bundle.putString(PARCEL_SERVICE_UUID, characteristic.getService().getUuid().toString());
bundle.putByteArray(PARCEL_VALUE, characteristic.getValue());
Message msg = Message.obtain(activity_handler,
GATT_CHARACTERISTIC_READ);
msg.setData(bundle);
msg.sendToTarget();
} else {
Log.d(Constants.TAG, "failed to read characteristic:"+characteristic.getUuid().toString()+" of service "+characteristic.getService().getUuid().toString()+" : status="+status);
sendConsoleMessage("characteristic read err:"+status);
}
}
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
Log.d(Constants.TAG, "onCharacteristicWrite");
if (status == BluetoothGatt.GATT_SUCCESS) {
Bundle bundle = new Bundle();
bundle.putString(PARCEL_CHARACTERISTIC_UUID, characteristic.getUuid().toString());
bundle.putString(PARCEL_SERVICE_UUID, characteristic.getService().getUuid().toString());
bundle.putByteArray(PARCEL_VALUE, characteristic.getValue());
Message msg = Message.obtain(activity_handler, GATT_CHARACTERISTIC_WRITTEN);
msg.setData(bundle);
msg.sendToTarget();
} else {
sendConsoleMessage("characteristic write err:" + status);
}
}
};
}
I forgot to add the service in the Manifest as this:
<service
android:name=".bluetooth.BleAdapterService"
android:enabled="true" />
i'm trying to pass one array
[the array is inizialized by me {1,2,3,4} and i associate the string "txx"]
between two activity but i recive this error
java.lang.runtimeexception: unable to start activity
componentinfo{com.example.android.bluetoothlegatt/com.example.android.bluetoothlegatt.graphcurrentactivity}:
java.lang.nullpointerexception: attempt to read from null array
from debug mode i see that this array doesn't pass between two activity. i think that there can be an error in delcaration private/public variable..
please help me
activity A
public class BluetoothLeService extends Service {
private final static String TAG = BluetoothLeService.class.getSimpleName();
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt;
private int mConnectionState = STATE_DISCONNECTED;
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTING = 1;
private static final int STATE_CONNECTED = 2;
public final static String ACTION_GATT_CONNECTED =
"com.example.bluetooth.le.ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_DISCONNECTED =
"com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED =
"com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE =
"com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA =
"com.example.bluetooth.le.EXTRA_DATA";
public final static String EXTRA_DATA2 =
"com.example.bluetooth.le.EXTRA_DATA2";
public final static String EXTRA_DATA3 =
"com.example.bluetooth.le.EXTRA_DATA3";
public final static String EXTRA_DATA4 =
"com.example.bluetooth.le.EXTRA_DATA4";
public final static String EXTRA_DATA5 =
"com.example.bluetooth.le.EXTRA_DATA5";
public final static String EXTRA_DATA6 =
"com.example.bluetooth.le.EXTRA_DATA6";
public final static String EXTRA_DATA7 =
"com.example.bluetooth.le.EXTRA_DATA7";
byte[] value;
int[] data_info = new int[6];
public int[] grap_curr = new int[] {0,0,0,0,0,0,0,0,0,0};
public int[] grap_volt = new int[] {0,0,0,0,0,0,0,0,0,0};
public int[] grap_temp = new int[] {0,0,0,0,0,0,0,0,0,0};
public int[] grap_soc = new int[] {0,0,0,0,0,0,0,0,0,0};
public int[] grap_soh = new int[] {0,0,0,0,0,0,0,0,0,0};
int i = 0;
int j = 0;
public final static UUID UUID_USER_DATA =
UUID.fromString(SampleGattAttributes.FIRST_NAME);
public ArrayList<String> receivedPackets = new ArrayList<String>();
// Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
private void broadcastUpdate(final String action,final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
/* Creo le Intent per passare i dati da visualizzare sui grafici alle altre classi */
Intent intentCurr = new Intent(getApplicationContext(), GraphCurrentActivity.class);
//final Intent intentVolt = new Intent(getApplicationContext(), GraphVoltageActivity.class);
//final Intent intentTemp = new Intent(getApplicationContext(), GraphTempActivity.class);
//final Intent intentSoC = new Intent(getApplicationContext(), GraphSoCActivity.class);
//final Intent intentSoH = new Intent(getApplicationContext(), GraphSoHActivity.class);
if (UUID_USER_DATA.equals(characteristic.getUuid())) {
int flag = characteristic.getProperties();
int format = -1;
if ((flag & 0x01) != 0) {
format = BluetoothGattCharacteristic.FORMAT_UINT16;
Log.d(TAG, "Value format UINT16.");
} else {
format = BluetoothGattCharacteristic.FORMAT_UINT8;
Log.d(TAG, "Value format UINT8.");
}
value = characteristic.getValue();
ByteBuffer bb = ByteBuffer.wrap(value);
bb.order(ByteOrder.LITTLE_ENDIAN);
i++;
if (value != null && value.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(value.length);
for(byte byteChar : value)
stringBuilder.append(String.format("%02X ", byteChar));
//su value ho la stringa ricevuta, quindi posso elaborare il dato per far si che leggo sulla app quello che voglio
Byte b5 = value[5];
Byte b6 = value[6];
Byte b7 = value[7];
data_info[0] = ((value[1] << 8) | (value [2] & 0xFF));//current
data_info[1] = ((value[3] << 8) | (value [4] & 0xFF));//voltage
data_info[2] = b5.intValue();//soc
data_info[3] = b6.intValue();//temp
data_info[4] = b7.intValue();//soh
data_info[5] = ((value[8] << 8) | (value [9] & 0xFF));
//preparo i dati da passare alle alre activity
grap_curr[j]=data_info[2];
grap_volt[j]=data_info[2];
grap_temp[j]=data_info[2];
grap_soc[j]=data_info[2];
grap_soh[j]=data_info[2];
j++;
//dopo 10 cicli invio ai grafici
if (j==3){
intent.putExtra(EXTRA_DATA7, "Riepilogo temporale disponibile");
Bundle curr =new Bundle (); //array da mandare alla activity GraphCurrentActivity
curr.putIntArray("txxx",new int[] {1,2,3,4});
intentCurr.putExtras(curr);
//intentCurr.putExtra("tx",grap_curr);
//intentCurr.putExtra("datavectorcurr",new int[] {1,2,3,4,5,6,7,8,9,10});
//intentVolt.putExtra("datavectorvolt",new int[] {1,2,3,4,5,6,7,8,9,10});
//intentTemp.putExtra("datavectortemp",new int[] {1,2,3,4,5,6,7,8,9,10});
//intentSoC.putExtra("datavectorsoc",new int[] {1,2,3,4,5,6,7,8,9,10});
//intentSoH.putExtra("datavectorsoh",new int[] {1,2,3,4,5,6,7,8,9,10});
j=0;
}
//inserisco i dati negli appositi campi
intent.putExtra(EXTRA_DATA, "Battery Current: " + Integer.toString(data_info[0]) + " [A]" );
intent.putExtra(EXTRA_DATA2, "Battery Voltage: " + Integer.toString(data_info[1]) + " [V]" );
intent.putExtra(EXTRA_DATA3, "SOC: " + Integer.toString(data_info[2]) + " [Ah]" );
intent.putExtra(EXTRA_DATA4, "SOH: " + Integer.toString(data_info[4]) + " [%]");
intent.putExtra(EXTRA_DATA5, "average temperature: " + Integer.toString(data_info[3]) + " [°C]");
intent.putExtra(EXTRA_DATA6, "remaining capacity: " + Integer.toString(data_info[5]) + " [°Ah]");
}
}
sendBroadcast(intent);
}
public class LocalBinder extends Binder {
BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
// After using a given device, you should make sure that BluetoothGatt.close() is called
// such that resources are cleaned up properly. In this particular example, close() is
// invoked when the UI is disconnected from the Service.
close();
return super.onUnbind(intent);
}
private final IBinder mBinder = new LocalBinder();
/**
* Initializes a reference to the local Bluetooth adapter.
*
* #return Return true if the initialization is successful.
*/
public boolean initialize() {
// For API level 18 and above, get a reference to BluetoothAdapter through
// BluetoothManager.
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
Log.e(TAG, "Unable to initialize BluetoothManager.");
return false;
}
}
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
return true;
}
/**
* Connects to the GATT server hosted on the Bluetooth LE device.
*
* #param address The device address of the destination device.
*
* #return Return true if the connection is initiated successfully. The connection result
* is reported asynchronously through the
* {#code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
// Previously connected device. Try to reconnect.
if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
}
// We want to directly connect to the device, so we are setting the autoConnect
// parameter to false.
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
Log.d(TAG, "Trying to create a new connection.");
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
/**
* Disconnects an existing connection or cancel a pending connection. The disconnection result
* is reported asynchronously through the
* {#code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.disconnect();
}
/**
* After using a given BLE device, the app must call this method to ensure resources are
* released properly.
*/
public void close() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
}
/**
* Request a read on a given {#code BluetoothGattCharacteristic}. The read result is reported
* asynchronously through the {#code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}
* callback.
*
* #param characteristic The characteristic to read from.
*/
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
/**
* Enables or disables notification on a give characteristic.
*
* #param characteristic Characteristic to act on.
* #param enabled If true, enable notification. False otherwise.
*/
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
// This is specific to Heart Rate Measurement.
if (UUID_USER_DATA.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
/**
* Retrieves a list of supported GATT services on the connected device. This should be
* invoked only after {#code BluetoothGatt#discoverServices()} completes successfully.
*
* #return A {#code List} of supported services.
*/
public List<BluetoothGattService> getSupportedGattServices() {
if (mBluetoothGatt == null) return null;
return mBluetoothGatt.getServices();
}
public void readCustomCharacteristic() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
/*check if the service is available on the device*/
BluetoothGattService mCustomService = mBluetoothGatt.getService(UUID.fromString("0000181c-0000-1000-8000-00805f9b34fb"));
if(mCustomService == null){
Log.w(TAG, "Custom BLE Service not found");
return;
}
BluetoothGattCharacteristic mNotifyCharacteristic = mCustomService.getCharacteristic(UUID.fromString("00002a8a-0000-1000-8000-00805f9b34fb"));
UUID uuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
BluetoothGattDescriptor descriptor = mNotifyCharacteristic.getDescriptor(uuid);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
//To receive notification in Android is mandatory to set characteristic notification to true
mBluetoothGatt.setCharacteristicNotification(mNotifyCharacteristic, true);
/*get the read characteristic from the service*/
BluetoothGattCharacteristic mReadCharacteristic = mCustomService.getCharacteristic(UUID.fromString("00002A8A-0000-1000-8000-00805F9B34FB"));
if(mBluetoothGatt.readCharacteristic(mReadCharacteristic) == false){
Log.w(TAG, "Failed to read characteristic");
}
}
public void writeCustomCharacteristic(int value) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
/*check if the service is available on the device*/
BluetoothGattService mCustomService = mBluetoothGatt.getService(UUID.fromString("0000181c-0000-1000-8000-00805f9b34fb"));
if(mCustomService == null){
Log.w(TAG, "Custom BLE Service not found");
return;
}
/*get the write characteristic from the service*/
BluetoothGattCharacteristic mWriteCharacteristic = mCustomService.getCharacteristic(UUID.fromString("00002a8a-0000-1000-8000-00805f9b34fb"));
mWriteCharacteristic.setValue(value,android.bluetooth.BluetoothGattCharacteristic.FORMAT_UINT8,0);
if(mBluetoothGatt.writeCharacteristic(mWriteCharacteristic) == false){
Log.w(TAG, "Failed to write characteristic");
}
}
}
activty B
public class GraphCurrentActivity extends Activity {
private XYPlot plot;
private GoogleApiClient client;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
// initialize our XYPlot reference:
plot = (XYPlot) findViewById(R.id.plot);
Bundle b=this.getIntent().getExtras();
int[] arraydata;
arraydata = b.getIntArray("txxx");//array that i don't recive
// create a couple arrays of y-values to plot:
final Number[] domainLabels = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
//Number[] series1Numbers = {plottdata[0], plottdata[1], plottdata[2], plottdata[3], plottdata[4], plottdata[5], plottdata[6], plottdata[7], plottdata[8], plottdata[9]};
Number[] series1Numbers = {11, 12, 13, 14, 0, 5, 8, 7, 1, 11};
// turn the above arrays into XYSeries':
// (Y_VALS_ONLY means use the element index as the x value)
XYSeries series1 = new SimpleXYSeries(
Arrays.asList(series1Numbers), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Battery Current Plot");
LineAndPointFormatter series1Format = new LineAndPointFormatter(Color.RED, Color.GREEN, Color.BLUE, null);
series1Format.setInterpolationParams(
new CatmullRomInterpolator.Params(10, CatmullRomInterpolator.Type.Centripetal));
// add a new series' to the xyplot:
plot.addSeries(series1, series1Format);
plot.getGraph().getLineLabelStyle(XYGraphWidget.Edge.BOTTOM).setFormat(new Format() {
#Override
public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
int i = Math.round(((Number) obj).floatValue());
return toAppendTo.append(domainLabels[i]);
}
#Override
public Object parseObject(String source, ParsePosition pos) {
return null;
}
});
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
public Action getIndexApiAction() {
Thing object = new Thing.Builder()
.setName("GraphCurrent Page") // TODO: Define a title for the content shown.
// TODO: Make sure this auto-generated URL is correct.
.setUrl(Uri.parse("http://[ENTER-YOUR-URL-HERE]"))
.build();
return new Action.Builder(Action.TYPE_VIEW)
.setObject(object)
.setActionStatus(Action.STATUS_TYPE_COMPLETED)
.build();
}
#Override
public void onStart() {
super.onStart();
client.connect();
AppIndex.AppIndexApi.start(client, getIndexApiAction());
}
#Override
public void onStop() {
super.onStop();
AppIndex.AppIndexApi.end(client, getIndexApiAction());
client.disconnect();
}
}
Best solution I can suggest is define your array as
public static int[] xyz=new int[]{1,2,3,4};
And now that static int array can be called or used from any activity provided if they are in the same package.
Here for your example in GraphCurrentActivity,
Add this import statement:
import static yourpackagename.BluetoothLeService.xyz;
//And these lines to read that array:
int[] arraydata;
arraydata = xyz;
And let me know if this was wrong.
I am developing an Android app to control stepper motors via a Android Due and a Bluetooth HM-10 BLE module.
So far everything works, but there seems to be a problem on some devices, which cause the app to crash. On my Nexus 5 and 7 it is working fine, but for example on a Samsung Galaxy S5 it keeps crashing. All devices have Andoird 6.0.1, so they should be equal.
I am getting this error report from the user:
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.bluetooth.BluetoothGattCharacteristic.setValue(byte[])' on a null object reference
at pm.puremoco.BluetoothLeService.WriteValue(BluetoothLeService.java:70)
at pm.puremoco.frag_moviesetlinear$3.onFinish(frag_moviesetlinear.java:266)
at android.os.CountDownTimer$1.handleMessage(CountDownTimer.java:127)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7224)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
So the error is occuring, when opening, at "onCreateView". There is the command to transmit a value:
mBluetoothLeService.WriteValue("1900_" + String.valueOf(variables.vidUpdateIntervall) + "#");
Here is almost the full fragment:
public class frag_moviesetlinear extends Fragment {
public static final String methodtocall = "ooo";
private final static String TAG = DeviceControlFragment.class.getSimpleName();
public AlertDialog alertTransmitData;
public BluetoothLeService mBluetoothLeService; //TODO evtl. private
public String methodcalled = "aaa";
public String dataLineReceived;
public long countDownTimerDelay = 200;
public AlertDialog alertTimeTooShort;
NumberPicker noPick1 = null;
NumberPicker noPick2 = null;
NumberPicker noPick3 = null;
long alertTransmitDataLength = 21000;
DeviceControlFragment devConFrag;
double minTimeFactor = 0;
TextView vid_maxSpeedU;
TextView vid_maxSpeedV;
TextView vid_maxSpeedW;
TextView vid_maxSpeedX;
TextView vid_maxSpeedY;
TextView vid_maxSpeedZ;
TextView vid_maxSpeedUspline;
TextView vid_maxSpeedVspline;
TextView vid_maxSpeedWspline;
TextView vid_maxSpeedXspline;
TextView vid_maxSpeedYspline;
TextView vid_maxSpeedZspline;
TextView txt_vidDuration;
TextView txt_vidUpdateIntervall;
TextView txt_minTime;
int timeForCalculation = 0;
int calculatedSpeedU = 0;
int calculatedSpeedV = 0;
int calculatedSpeedW = 0;
int calculatedSpeedX = 0;
int calculatedSpeedY = 0;
int calculatedSpeedZ = 0;
boolean movingHome = false;
private String mDeviceAddress;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
if (!mBluetoothLeService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
getActivity().finish();
}
Log.e(TAG, "mBluetoothLeService is okay");
// Log.e(TAG, mDeviceAddress);
// Automatically connects to the device upon successful start-up initialization.
if (mDeviceAddress == "---") {
Toast.makeText(getActivity(), "Bluetooth-Device not selected!", Toast.LENGTH_SHORT).show();
} else {
mBluetoothLeService.connect(mDeviceAddress);
}
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mBluetoothLeService = null;
}
};
private String mDeviceName;
private TextView mDataField;
private Button btn_vidSplineStart;
private Button btn_vidUpdateIntervalNeg;
private Button btn_vidUpdateIntervalPos;
private boolean mConnected = false;
// Handles various events fired by the Service.
// ACTION_GATT_CONNECTED: connected to a GATT server.
// ACTION_GATT_DISCONNECTED: disconnected from a GATT server.
// ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.
// ACTION_DATA_AVAILABLE: received data from the device. This can be a result of read
// or notification operations.
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) { //���ӳɹ�
Log.e(TAG, "Only gatt, just wait");
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) { //�Ͽ�����
mConnected = false;
getActivity().invalidateOptionsMenu();
// btnSend.setEnabled(false);
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) //���Կ�ʼ�ɻ���
{
mConnected = true;
// mDataField.setText("");
// ShowDialog();
//btnSend.setEnabled(true);
Log.e(TAG, "In what we need");
getActivity().invalidateOptionsMenu();
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) { //�յ�����
Log.e(TAG, "RECV DATA");
final String data = intent.getStringExtra(BluetoothLeService.EXTRA_DATA);
Log.e(TAG, data);
if (data != null && data.substring(0, 1).equals("#") && data.substring(data.length() - 1).equals("$")) {
// if (mDataField.length() > 500)
// mDataField.setText("");
// mDataField.append(data);
dataLineReceived = data.substring(1, data.length() - 1);
ActionHandlerDataReceived();
}
}
}
};
private static IntentFilter makeGattUpdateIntentFilter() { //ע����յ��¼�
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
intentFilter.addAction(BluetoothDevice.ACTION_UUID);
return intentFilter;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
final Intent intent = getActivity().getIntent();
// mDeviceName = intent.getStringExtra(EXTRAS_DEVICE_NAME);
// mDeviceAddress = intent.getStringExtra(EXTRAS_DEVICE_ADDRESS);
mDeviceAddress = variables.BluetoothAddress;
mDeviceName = variables.BluetoothName;
methodcalled = intent.getStringExtra(methodtocall);
Intent gattServiceIntent = new Intent(getActivity(), BluetoothLeService.class);
Log.d(TAG, "Try to bindService=" + getActivity().bindService(gattServiceIntent, mServiceConnection, getActivity().BIND_AUTO_CREATE));
getActivity().registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
#Override
public void onPause() {
super.onPause();
try {
getActivity().unregisterReceiver(mGattUpdateReceiver);
}
catch(Exception e){
}
try {
getActivity().unbindService(mServiceConnection);
}
catch(Exception e){
}
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "We are in destroy");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.setmovie, null);
vid_maxSpeedU = (TextView) layout.findViewById(R.id.vid_maxSpeedU);
vid_maxSpeedU.setText(String.valueOf(variables.speedU));
vid_maxSpeedV = (TextView) layout.findViewById(R.id.vid_maxSpeedV);
vid_maxSpeedV.setText(String.valueOf(variables.speedV));
vid_maxSpeedW = (TextView) layout.findViewById(R.id.vid_maxSpeedW);
vid_maxSpeedW.setText(String.valueOf(variables.speedW));
vid_maxSpeedX = (TextView) layout.findViewById(R.id.vid_maxSpeedX);
vid_maxSpeedX.setText(String.valueOf(variables.speedX));
vid_maxSpeedY = (TextView) layout.findViewById(R.id.vid_maxSpeedY);
vid_maxSpeedY.setText(String.valueOf(variables.speedY));
vid_maxSpeedZ = (TextView) layout.findViewById(R.id.vid_maxSpeedZ);
vid_maxSpeedZ.setText(String.valueOf(variables.speedZ));
double duration = 3700 * (double) variables.vidUpdateIntervall / 1000;
txt_vidUpdateIntervall = (TextView) layout.findViewById(R.id.txt_vidUpdateIntervall);
txt_vidUpdateIntervall.setText(String.valueOf(variables.vidUpdateIntervall));
txt_vidDuration = (TextView) layout.findViewById(R.id.txt_vidDuration);
txt_vidDuration.setText(String.format("%.2f", duration) + " s");
vid_maxSpeedUspline = (TextView) layout.findViewById(R.id.vid_maxSpeedUspline);
vid_maxSpeedVspline = (TextView) layout.findViewById(R.id.vid_maxSpeedVspline);
vid_maxSpeedWspline = (TextView) layout.findViewById(R.id.vid_maxSpeedWspline);
vid_maxSpeedXspline = (TextView) layout.findViewById(R.id.vid_maxSpeedXspline);
vid_maxSpeedYspline = (TextView) layout.findViewById(R.id.vid_maxSpeedYspline);
vid_maxSpeedZspline = (TextView) layout.findViewById(R.id.vid_maxSpeedZspline);
txt_minTime = (TextView) layout.findViewById(R.id.txt_minTime);
btn_vidSplineStart = (Button) layout.findViewById(R.id.btn_vidSplineStart);
btn_vidSplineStart.setOnClickListener(new event_btn_vidSplineStart());
btn_vidUpdateIntervalPos = (Button) layout.findViewById(R.id.btn_vidUpdateIntervalPos);
btn_vidUpdateIntervalPos.setOnClickListener(new event_btn_vidUpdateIntervalPos());
btn_vidUpdateIntervalNeg = (Button) layout.findViewById(R.id.btn_vidUpdateIntervalNeg);
btn_vidUpdateIntervalNeg.setOnClickListener(new event_btn_vidUpdateIntervalNeg());
//-----start-button------
minTimeFactor = 0;
timeForCalculation = variables.vidUpdateIntervall;
new CountDownTimer(countDownTimerDelay * 1, 1) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
mBluetoothLeService.WriteValue("1900_" + String.valueOf(variables.vidUpdateIntervall) + "#");
}
}.start();
new CountDownTimer(countDownTimerDelay * 2, 1) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
mBluetoothLeService.WriteValue("2000_" + String.valueOf(variables.linearWithFade) + "#");
}
}.start();
//-----start-button------
transmitDataAlert("calculation");
return layout;
}
private void ActionHandlerDataReceived() {
String variable;
String value;
String[] parts = dataLineReceived.split("_"); // escape .
variable = parts[0];
value = parts[1];
switch (variable) {
case "vidMaxSpeedU":
vid_maxSpeedUspline.setText(String.valueOf(value));
variables.vid_maxSpeedUspline = Integer.parseInt(value);
calculatedSpeedU = Integer.parseInt(value);
if (Integer.parseInt(value) > variables.speedU) {
vid_maxSpeedUspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedUspline.setTextColor(Color.parseColor("#FF14AA00"));
}
double FactorU = Double.valueOf(value) / variables.speedU;
if (minTimeFactor < FactorU) {
minTimeFactor = FactorU;
}
break;
case "vidMaxSpeedV":
vid_maxSpeedVspline.setText(String.valueOf(value));
variables.vid_maxSpeedVspline = Integer.parseInt(value);
calculatedSpeedV = Integer.parseInt(value);
if (Integer.parseInt(value) > variables.speedV) {
vid_maxSpeedVspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedVspline.setTextColor(Color.parseColor("#FF14AA00"));
}
double FactorV = Double.valueOf(value) / variables.speedV;
if (minTimeFactor < FactorV) {
minTimeFactor = FactorV;
}
break;
case "vidMaxSpeedW":
vid_maxSpeedWspline.setText(String.valueOf(value));
variables.vid_maxSpeedWspline = Integer.parseInt(value);
calculatedSpeedW = Integer.parseInt(value);
if (Integer.parseInt(value) > variables.speedW) {
vid_maxSpeedWspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedWspline.setTextColor(Color.parseColor("#FF14AA00"));
}
double FactorW = Double.valueOf(value) / variables.speedW;
if (minTimeFactor < FactorW) {
minTimeFactor = FactorW;
}
break;
case "vidMaxSpeedX":
vid_maxSpeedXspline.setText(String.valueOf(value));
variables.vid_maxSpeedXspline = Integer.parseInt(value);
calculatedSpeedX = Integer.parseInt(value);
if (Integer.parseInt(value) > variables.speedX) {
vid_maxSpeedXspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedXspline.setTextColor(Color.parseColor("#FF14AA00"));
}
double FactorX = Double.valueOf(value) / variables.speedX;
if (minTimeFactor < FactorX) {
minTimeFactor = FactorX;
}
break;
case "vidMaxSpeedY":
vid_maxSpeedYspline.setText(String.valueOf(value));
variables.vid_maxSpeedYspline = Integer.parseInt(value);
calculatedSpeedY = Integer.parseInt(value);
if (Integer.parseInt(value) > variables.speedY) {
vid_maxSpeedYspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedYspline.setTextColor(Color.parseColor("#FF14AA00"));
}
double FactorY = Double.valueOf(value) / variables.speedY;
if (minTimeFactor < FactorY) {
minTimeFactor = FactorY;
}
break;
case "vidMaxSpeedZ":
vid_maxSpeedZspline.setText(String.valueOf(value));
variables.vid_maxSpeedZspline = Integer.parseInt(value);
calculatedSpeedZ = Integer.parseInt(value);
if (Integer.parseInt(value) > variables.speedZ) {
vid_maxSpeedZspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedZspline.setTextColor(Color.parseColor("#FF14AA00"));
}
double FactorZ = Double.valueOf(value) / variables.speedZ;
if (minTimeFactor < FactorZ) {
minTimeFactor = FactorZ;
}
alertTransmitData.dismiss();
double vidMin = Math.ceil(minTimeFactor * timeForCalculation);
variables.vidMinIntervall = (int) vidMin;
//txt_minTime.setText(String.valueOf(variables.vidMinIntervall));
double duration = (3700 * (double) variables.vidMinIntervall) / 1000;
txt_minTime.setText(String.format("%.2f", duration) + " s");
if(variables.vidMinIntervall<=variables.vidUpdateIntervall) {
btn_vidSplineStart.setEnabled(true);
}
break;
case "movieFinished":
btn_vidSplineStart.setText("Move home");
btn_vidSplineStart.setEnabled(true);
movingHome = true;
alertTransmitData.dismiss();
break;
case "movieHome":
btn_vidSplineStart.setText("Start");
btn_vidSplineStart.setEnabled(true);
alertTransmitData.dismiss();
break;
}
}
void calculateNewSpeeds() {
//--------------U-Axis-----------------
if (variables.vid_maxSpeedUspline != 0) {
variables.vid_maxSpeedUspline = (timeForCalculation * calculatedSpeedU) / variables.vidUpdateIntervall;
vid_maxSpeedUspline.setText(String.valueOf(variables.vid_maxSpeedUspline));
if (variables.vid_maxSpeedUspline > variables.speedU) {
vid_maxSpeedUspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedUspline.setTextColor(Color.parseColor("#FF14AA00"));
}
}
//--------------V-Axis-----------------
if (variables.vid_maxSpeedVspline != 0) {
variables.vid_maxSpeedVspline = (timeForCalculation * calculatedSpeedV) / variables.vidUpdateIntervall;
vid_maxSpeedVspline.setText(String.valueOf(variables.vid_maxSpeedVspline));
if (variables.vid_maxSpeedVspline > variables.speedV) {
vid_maxSpeedVspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedVspline.setTextColor(Color.parseColor("#FF14AA00"));
}
}
//--------------W-Axis-----------------
if (variables.vid_maxSpeedWspline != 0) {
variables.vid_maxSpeedWspline = (timeForCalculation * calculatedSpeedW) / variables.vidUpdateIntervall;
vid_maxSpeedWspline.setText(String.valueOf(variables.vid_maxSpeedWspline));
if (variables.vid_maxSpeedWspline > variables.speedW) {
vid_maxSpeedWspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedWspline.setTextColor(Color.parseColor("#FF14AA00"));
}
}
//--------------X-Axis-----------------
if (variables.vid_maxSpeedXspline != 0) {
variables.vid_maxSpeedXspline = (timeForCalculation * calculatedSpeedX) / variables.vidUpdateIntervall;
vid_maxSpeedXspline.setText(String.valueOf(variables.vid_maxSpeedXspline));
if (variables.vid_maxSpeedXspline > variables.speedX) {
vid_maxSpeedXspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedXspline.setTextColor(Color.parseColor("#FF14AA00"));
}
}
//--------------Y-Axis-----------------
if (variables.vid_maxSpeedYspline != 0) {
variables.vid_maxSpeedYspline = (timeForCalculation * calculatedSpeedY) / variables.vidUpdateIntervall;
vid_maxSpeedYspline.setText(String.valueOf(variables.vid_maxSpeedYspline));
if (variables.vid_maxSpeedYspline > variables.speedY) {
vid_maxSpeedYspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedYspline.setTextColor(Color.parseColor("#FF14AA00"));
}
}
//--------------Z-Axis-----------------
if (variables.vid_maxSpeedZspline != 0) {
variables.vid_maxSpeedZspline = (timeForCalculation * calculatedSpeedZ) / variables.vidUpdateIntervall;
vid_maxSpeedZspline.setText(String.valueOf(variables.vid_maxSpeedZspline));
if (variables.vid_maxSpeedZspline > variables.speedZ) {
vid_maxSpeedZspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedZspline.setTextColor(Color.parseColor("#FF14AA00"));
}
}
}
public void alert_TimeTooShort(int errorCase, int movieLengthSecondsNEW) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
getActivity());
// set title
alertDialogBuilder.setTitle("Error");
String errorMessage = "error";
// set dialog message
alertDialogBuilder
.setMessage(errorMessage)
.setCancelable(false);
alertDialogBuilder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// continue with delete
}
});
// create alert dialog
alertTimeTooShort = alertDialogBuilder.create();
// show it
alertTimeTooShort.show();
}
public void transmitDataAlert(String type) {
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
View promptView = layoutInflater.inflate(R.layout.alert_transmitdata, null);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
alertDialogBuilder.setView(promptView);
final ProgressBar progressbar = (ProgressBar) promptView.findViewById(R.id.progressBar_transmitData);
final TextView txt_PleaseWait = (TextView) promptView.findViewById(R.id.txt_PleaseWait);
final TextView txt_timeRemainVideo = (TextView) promptView.findViewById(R.id.txt_timeRemainVideo);
final TextView txt_timeRemainVideoTXT = (TextView) promptView.findViewById(R.id.txt_timeRemainVideoTXT);
new CountDownTimer(alertTransmitDataLength, 1) {
public void onTick(long millisUntilFinished) {
int longtointRemain = (int) millisUntilFinished;
int longtointFull = (int) alertTransmitDataLength;
int percentprogress = 100 - ((100 * longtointRemain) / longtointFull);
progressbar.setProgress(percentprogress);
float duration = (float) millisUntilFinished/1000;
txt_timeRemainVideo.setText(String.format("%.1f", duration) + " s");
}
public void onFinish() {
}
}.start();
}
alertDialogBuilder.setCancelable(false);
alertTransmitData = alertDialogBuilder.create();
alertTransmitData.show();
}
class event_btn_vidSplineStart implements View.OnClickListener {
#Override
public void onClick(View v) {
btn_vidSplineStart.setEnabled(false);
btn_vidSplineStart.setText("Moving...");
new CountDownTimer(countDownTimerDelay * 1, 1) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
//MotionMode
mBluetoothLeService.WriteValue("1900_" + String.valueOf(variables.vidUpdateIntervall) + "#");
}
}.start();
new CountDownTimer(countDownTimerDelay * 2, 1) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
//MotionMode
mBluetoothLeService.WriteValue("1110_0#");
}
}.start();
alertTransmitDataLength = (long) variables.vidUpdateIntervall*3700;
if(movingHome==true){
transmitDataAlert("moveHome");
movingHome=false;
}
else {
transmitDataAlert("videomove");
}
}
}
class event_btn_vidUpdateIntervalPos implements View.OnClickListener {
#Override
public void onClick(View v) {
variables.vidUpdateIntervall++;
double duration = (3700 * (double) variables.vidUpdateIntervall) / 1000;
txt_vidDuration.setText(String.format("%.2f", duration) + " s");
txt_vidUpdateIntervall.setText(String.valueOf(variables.vidUpdateIntervall));
calculateNewSpeeds();
if(variables.vidMinIntervall<=variables.vidUpdateIntervall) {
btn_vidSplineStart.setEnabled(true);
}
else{
btn_vidSplineStart.setEnabled(false);
}
}
}
class event_btn_vidUpdateIntervalNeg implements View.OnClickListener {
#Override
public void onClick(View v) {
if (variables.vidUpdateIntervall > 1) {
variables.vidUpdateIntervall--;
}
double duration = (3700 * (double) variables.vidUpdateIntervall) / 1000;
txt_vidDuration.setText(String.format("%.2f", duration) + " s");
txt_vidUpdateIntervall.setText(String.valueOf(variables.vidUpdateIntervall));
calculateNewSpeeds();
if(variables.vidMinIntervall<=variables.vidUpdateIntervall) {
btn_vidSplineStart.setEnabled(true);
}
else{
btn_vidSplineStart.setEnabled(false);
}
}
}
}
And here is the full BluetoothLeService, which I got from the website of the HM-10 Bluetooth manufacturer:
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
import java.util.List;
import java.util.UUID;
/**
* Service for managing connection and data communication with a GATT server hosted on a
* given Bluetooth LE device.
*/
public class BluetoothLeService extends Service {
private final static String TAG = BluetoothLeService.class.getSimpleName();
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothGatt mBluetoothGatt;
public final static String ACTION_GATT_CONNECTED =
"com.example.bluetooth.le.ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_DISCONNECTED =
"com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED =
"com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE =
"com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA =
"com.example.bluetooth.le.EXTRA_DATA";
public final static UUID UUID_NOTIFY =
UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb");
public final static UUID UUID_SERVICE =
UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb");
public BluetoothGattCharacteristic mNotifyCharacteristic;
public void WriteValue(String strValue)
{
mNotifyCharacteristic.setValue(strValue.getBytes());
mBluetoothGatt.writeCharacteristic(mNotifyCharacteristic);
}
public void findService(List<BluetoothGattService> gattServices)
{
Log.i(TAG, "Count is:" + gattServices.size());
for (BluetoothGattService gattService : gattServices)
{
Log.i(TAG, gattService.getUuid().toString());
Log.i(TAG, UUID_SERVICE.toString());
if(gattService.getUuid().toString().equalsIgnoreCase(UUID_SERVICE.toString()))
{
List<BluetoothGattCharacteristic> gattCharacteristics =
gattService.getCharacteristics();
Log.i(TAG, "Count is:" + gattCharacteristics.size());
for (BluetoothGattCharacteristic gattCharacteristic :
gattCharacteristics)
{
if(gattCharacteristic.getUuid().toString().equalsIgnoreCase(UUID_NOTIFY.toString()))
{
Log.i(TAG, gattCharacteristic.getUuid().toString());
Log.i(TAG, UUID_NOTIFY.toString());
mNotifyCharacteristic = gattCharacteristic;
setCharacteristicNotification(gattCharacteristic, true);
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
return;
}
}
}
}
}
// Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
Log.i(TAG, "oldStatus=" + status + " NewStates=" + newState);
if(status == BluetoothGatt.GATT_SUCCESS)
{
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mBluetoothGatt.close();
mBluetoothGatt = null;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.w(TAG, "onServicesDiscovered received: " + status);
findService(gatt.getServices());
} else {
if(mBluetoothGatt.getDevice().getUuids() == null)
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
Log.e(TAG, "OnCharacteristicWrite");
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,
int status)
{
Log.e(TAG, "OnCharacteristicWrite");
}
#Override
public void onDescriptorRead(BluetoothGatt gatt,
BluetoothGattDescriptor bd,
int status) {
Log.e(TAG, "onDescriptorRead");
}
#Override
public void onDescriptorWrite(BluetoothGatt gatt,
BluetoothGattDescriptor bd,
int status) {
Log.e(TAG, "onDescriptorWrite");
}
#Override
public void onReadRemoteRssi(BluetoothGatt gatt, int a, int b)
{
Log.e(TAG, "onReadRemoteRssi");
}
#Override
public void onReliableWriteCompleted(BluetoothGatt gatt, int a)
{
Log.e(TAG, "onReliableWriteCompleted");
}
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
private void broadcastUpdate(final String action,
final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
// This is special handling for the Heart Rate Measurement profile. Data parsing is
// carried out as per profile specifications:
// http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
// For all other profiles, writes the data formatted in HEX.
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
//final StringBuilder stringBuilder = new StringBuilder(data.length);
//for(byte byteChar : data)
// stringBuilder.append(String.format("%02X ", byteChar));
//intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
intent.putExtra(EXTRA_DATA, new String(data));
}
sendBroadcast(intent);
}
public class LocalBinder extends Binder {
BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
// After using a given device, you should make sure that BluetoothGatt.close() is called
// such that resources are cleaned up properly. In this particular example, close() is
// invoked when the UI is disconnected from the Service.
close();
return super.onUnbind(intent);
}
private final IBinder mBinder = new LocalBinder();
/**
* Initializes a reference to the local Bluetooth adapter.
*
* #return Return true if the initialization is successful.
*/
public boolean initialize() {
// For API level 18 and above, get a reference to BluetoothAdapter through
// BluetoothManager.
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
Log.e(TAG, "Unable to initialize BluetoothManager.");
return false;
}
}
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
return true;
}
/**
* Connects to the GATT server hosted on the Bluetooth LE device.
*
* #param address The device address of the destination device.
*
* #return Return true if the connection is initiated successfully. The connection result
* is reported asynchronously through the
* {#code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
/*
// Previously connected device. Try to reconnect.
if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
}
*/
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
}
// We want to directly connect to the device, so we are setting the autoConnect
// parameter to false.
if(mBluetoothGatt != null)
{
mBluetoothGatt.close();
mBluetoothGatt = null;
}
mBluetoothGatt = device.connectGatt(this.getApplication(), false, mGattCallback);
//mBluetoothGatt.connect();
Log.d(TAG, "Trying to create a new connection.");
return true;
}
/**
* Disconnects an existing connection or cancel a pending connection. The disconnection result
* is reported asynchronously through the
* {#code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.disconnect();
}
/**
* After using a given BLE device, the app must call this method to ensure resources are
* released properly.
*/
public void close() {
/*
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
*/
}
/**
* Request a read on a given {#code BluetoothGattCharacteristic}. The read result is reported
* asynchronously through the {#code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}
* callback.
*
* #param characteristic The characteristic to read from.
*/
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
/**
* Enables or disables notification on a give characteristic.
*
* #param characteristic Characteristic to act on.
* #param enabled If true, enable notification. False otherwise.
*/
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
/*
// This is specific to Heart Rate Measurement.
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
*/
}
/**
* Retrieves a list of supported GATT services on the connected device. This should be
* invoked only after {#code BluetoothGatt#discoverServices()} completes successfully.
*
* #return A {#code List} of supported services.
*/
public List<BluetoothGattService> getSupportedGattServices() {
if (mBluetoothGatt == null) return null;
return mBluetoothGatt.getServices();
}
}