In Android's BLE API (BluetoothGatt) there are methods that deal with reliable writes:
public boolean beginReliableWrite ()
public void abortReliableWrite (BluetoothDevice mDevice)
public boolean executeReliableWrite ()
There is also a Callback for it (in BluetoothGattCallback):
public void onReliableWriteCompleted (BluetoothGatt gatt, int status)
I can't find any documentation on that. What is it? How is it different from "normal" (unreliable?) writes?
Reliable write allows checking back transmitted values and atomic execution of one or mutliple transmitted messages.
A good explaination of the reliable write procedure can be found in the BLE part of Mozillas Boot 2 Gecko Project documentation. Even though it's meant for JavaScript the description of beginReliableWrite() in particular is very helpful for understanding the process:
Once a reliable write transaction has been initiated, all calls to
characteristic.writeValue() are sent to the remote device for
verification and queued up for atomic execution. An Promise that
carries the written value is returned in response to every
characteristic.writeValue() call and the application is responsible
for verifying whether the value has been transmitted accurately. After
all characteristics have been queued up and verified,
executeReliableWrite() will execute all writes. If a characteristic
was not written correctly, calling abortReliableWrite() will cancel
the current transaction without committing any values on the remote LE
device.
You begin the reliable write,
gatt.beginReliableWrite();
set the value of the characteristic and write it.
characteristic.setValue(value);
gatt.writeCharacteristic(characteristic);
The writeCharacteristic() call will trigger its 'normal' callback. The parameter characteristic contains the actual, written value which can be verified:
#Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
...
if(characteristic.getValue() != value) {
gatt.abortReliableWrite();
} else {
gatt.executeReliableWrite();
}
...
}
Executing the reliable write will trigger the onReliableWriteCompleted(BluetoothGatt gatt, int status) callback.
Related
I am working with BLE device.I perform the code using android GATT and it scan device and also I send immediate alert in BLE device from mobile using writeCharacteristic and BLE device is beep.But now I want to Alert in android Mobile when I press BLE device button. That exactly I don't know how to do.
Thank You.
For this you have to listen for characteristics change. When you will press the BLE button, a characteristics must be change inside its hardware (set any flag value depends on hardware's firmware coding). When characteristics changed, characteristics method will called. You can perform required functionality there.
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic
characteristic)
{
Here we received ble button pressed event callback. Do stuff here.
}
For receiving characteristics change callback first you have to enable the notification like this.
BluetoothGattCharacteristic characteristic = gatt.getService(mServiceUuuid).getCharacteristic(mCharOneUuuid);
gatt.setCharacteristicNotification(characteristic, true);
List<BluetoothGattDescriptor> list = characteristic.getDescriptors();
for (int i = 0; i < list.size(); i++) {
BluetoothGattDescriptor desc = list.get(i);
desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(desc);
}
I'm analyzing a sample from android, which is explaining a bluetooth low energy usage on android. I've found the following code, which is setting a notification, but I can't get what is happening here with using a properties integer and conditions inside ifs. Could someone explain it a little bit?
Anyway, maybe you have some better source, which can explain a ble concept on android- what and how is working here? The official android tutorial is really poor, and bluetooth official page is giving almost nothing...
#Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
int childPosition, long id) {
if (mGattCharacteristics != null) {
final BluetoothGattCharacteristic characteristic =
mGattCharacteristics.get(groupPosition).get(childPosition);
final int charaProp = characteristic.getProperties();
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
// If there is an active notification on a characteristic, clear
// it first so it doesn't update the data field on the user interface.
if (mNotifyCharacteristic != null) {
mBluetoothLeService.setCharacteristicNotification(
mNotifyCharacteristic, false);
mNotifyCharacteristic = null;
}
mBluetoothLeService.readCharacteristic(characteristic);
}
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
mNotifyCharacteristic = characteristic;
mBluetoothLeService.setCharacteristicNotification(
characteristic, true);
}
return true;
}
return false;
}
You could try reading the Bluetooth specification (https://www.bluetooth.com/specifications/adopted-specifications, Core Version 5.0), vol 3 part G. Just note that Android abstracts away the attribute handles.
What most people do however is writing an app designed for a particular hardware, i.e. the gatt db is assumed to be known.
In order to get objects that represents the services, characteristics and descriptors, call gatt.discoverServices(). The result is returned asynchronously using the onServicesDiscovered() callback. This should be done each time a device gets connected (in the onConnectionStateChange callback when newState is GATT_CONNECTED).
To write to a characteristic, first set the value on the BluetoothGattCharacteristic object using the setValue method, then call gatt.writeCharacteristic(characteristic). When the operation is complete, onCharacteristicWrite will be called.
A read operation works in similar way; call gatt.readCharacteristic(characteristic) and the result is ready when the onCharacteristicRead is called. Use getValue() on the characteristic object to get the value.
For notifications to work you must first write BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE (0x0001) to the client characteristic configuration descriptor so that the peripheral will start deliver notifications. You must also tell the Android Bluetooth stack to forward the notifications to your app by calling setCharacteristicNotification.
Note that you can only have one outstanding operation at a time (read/write), meaning you must wait for the callback before you issue a new request.
If you know the hardware you're dealing with you normally don't need to inspect the characteristic properties (characteristic.getProperties()). The bitmask is described in Bluetooth Core V 5.0 specification, Vol 3, Part G, section 3.3.1.1 and describes what features are enabled for each characteristic (for example read, write, notifications).
How to deal with conversion between 16-bit and 128-bit UUIDs is shown in the Bluetooth Core V 5.0 specification, Vol 3, Part B, section 2.5.1. Note that Android's client libraries only use 128-bit UUIDs.
In my application, I got the READ and WRITE to work on specific BluetoothGattCharacteristic objects.
The BluetoothGattCallback onCharacteristicWrite and onCharacteristicRead are properly called.
I have then tried to setup the NOTIFY option so my Android app gets notified when a specific characteristic on the device changes.
I have set this up via the following code:
// Local notifications
mGatt.setCharacteristicNotification(statusTypeCharacteristic, notify);
// Remote notifications
BluetoothGattDescriptor desc = statusTypeCharacteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
Log.d("Descriptor", desc.toString());
boolean test;
test = desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); // return value = true
test = mGatt.writeDescriptor(desc); // return value = true
When the characteristic changes, the callback: onCharacteristicChanged is being called as expected
However, now all READ and WRITE operations do not work anymore.
When I comment the lines dealing with the descriptor, the READ and WRITE work again.
A part I am very unclear is around the UUID used to get the descriptor. Is it correct? Should I scan instead all descriptors from the characteristic and enable notification on one? How do I know which one to set as I have multiple ones coming back?
Ok, so I have figured out the issue.
At the beginning of my application, I am configuring (i.e. writing) to lots of descriptors.
2 issues with it:
1- A descriptor can only be written one at a time
2- No read/write operations can happen when a descriptor is being written to
The fix is to create a queue of write descriptor operations and perform the next descriptor write in the onDescriptorWrite callback.
private void writeGattDescriptor(BluetoothGattDescriptor d) {
//put the descriptor into the write queue
descriptorWriteQueue.add(d);
//if there is only 1 item in the queue, then write it. If more than 1, we handle asynchronously in the
// callback
if(descriptorWriteQueue.size() == 1) {
mGatt.writeDescriptor(d);
}
}
And then in the callback:
#Override
public void onDescriptorWrite (BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
// Called when the descriptor is updated for notification
Log.d("onDescriptorWrite", descriptor.getUuid().toString());
// pop the item that we just finishing writing
descriptorWriteQueue.remove();
// if there is more to write, do it!
if(descriptorWriteQueue.size() > 0) {
mGatt.writeDescriptor(descriptorWriteQueue.element());
}
// Inform the framework that the scope has connected, configured and ready to process commands
if(descriptorWriteQueue.size() == 0) {
// Do something else, such as reads and writes
}
}
I use a LeScanCallback (can not use the newer scan methods because I'm developing for api 18. Not that it matters, since the android 5.0+ apis don't offer this functionality either) to detect when a nearby BLE device is detected:
private BluetoothAdapter.LeScanCallback bleCallback = new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
discoveredDevices.add(bluetoothDevice);
}
};
I am not pairing or connecting with the devices because that's not required, I simply want to see which devices are nearby.
I'm trying to make a service that, every 5 mins or so, calls a webserver to update which devices are nearby at that moment.
Tricky part is that the android device will be moving, so a bluetooth device that is nearby right now, might not be in 5 mins. In that case I need to remove it from discoveredDevices.
Ideally, I would like to receive a callback when a bluetooth device was in range before, but is not anymore. This callback doesn't exist though.
(I'm aware of the android.bluetooth.device.action.ACL_CONNECTED and android.bluetooth.device.action.ACL_DISCONNECTED broadcasts, but those are for when you connect to a bluetooth device, which I don't want.)
An option is to do a fresh scan every 5 mins, but you can't tell when all nearby devices have been discovered, so you would have to do a timed scan, e.g. scan for 5 seconds and then send the collected data to the webservice.
This sounds dirty and risky because you can never know for sure all nearby devices were discovered within the allotted time, so I would very much like to avoid doing it like that.
Is there another way to do this?
Edit
Some devices continuously report discovery of nearby bluetooth devices, even if they were already discovered before. If that functionality was universal I could solve my problem, however this is device specific.
My phone's bluetooth adapter for example only discovers nearby devices once. Some other devices I have tested with do continuously report the same nearby devices, but not all devices do, so I can't rely on that unfortunately.
This sounds dirty and risky because you can never know for sure all nearby devices were discovered within the allotted time, so I would very much like to avoid doing it like that.
That sounds like a reasonable assumption, but it's wrong.
Bluetooth low energy works in a particular way and BLE devices have some limits. For instance, they have a fixed range of possible advertising frequencies, ranging from 20 milliseconds to 10.24 seconds, in steps of 0.625 milliseconds. See here and here for more detailed information.
This means that it can take at most 10.24 seconds before a device will broadcast a new advertisement package. BLE devices generally, if not always, provide a way for their owner to adjust their advertising frequency, so the frequency can of course vary.
In cases where you are periodically collecting data about nearby devices, like yours, it is fine to use a scan with a fixed time limit, save that data somewhere, restart the scan, collect new data, compare with old data --> get results.
For example, if a device was found in scan 1 but not in scan 2, you can conclude that the device was in range, but is not anymore.
Same goes for the other way around: if a device was found in scan 4 but not in scan 3, it is a newly discovered device.
Finally, if a device was found in scan 5, was not found in scan 6, but was again found in scan 7, it is rediscovered and can be handled as such if need be.
Because I'm answering my own question here, I'll add the code that I used to implement this.
I have the scanning done in a background service, and communicate to other parts of the app using BroadcastReceivers. Asset is a custom class of mine that holds some data. DataManager is a custom class of mine that - how did you guess it - manages data.
public class BLEDiscoveryService extends Service {
// Broadcast identifiers.
public static final String EVENT_NEW_ASSET = "EVENT_NEW_ASSET ";
public static final String EVENT_LOST_ASSET = "EVENT_LOST_ASSET ";
private static Handler handler;
private static final int BLE_SCAN_TIMEOUT = 11000; // 11 seconds
// Lists to keep track of current and previous detected devices.
// Used to determine which are in range and which are not anymore.
private List<Asset> previouslyDiscoveredAssets;
private List<Asset> currentlyDiscoveredAssets;
private BluetoothAdapter bluetoothAdapter;
private BluetoothAdapter.LeScanCallback BLECallback = new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
Asset asset = DataManager.getAssetForMACAddress(bluetoothDevice.getAddress());
handleDiscoveredAsset(asset);
}
};
#Override
public void onCreate() {
super.onCreate();
BluetoothManager manager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
bluetoothAdapter = manager.getAdapter();
previouslyDiscoveredAssets = new ArrayList<>();
currentlyDiscoveredAssets = new ArrayList<>();
handler = new Handler();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Start scanning.
startBLEScan();
// After a period of time, stop the current scan and start a new one.
// This is used to detect when assets are not in range anymore.
handler.postDelayed(new Runnable() {
#Override
public void run() {
performRepeatingTask();
// Repeat.
handler.postDelayed(this, BLE_SCAN_TIMEOUT);
}
}, BLE_SCAN_TIMEOUT);
// Service is not restarted if it gets terminated.
return Service.START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
handler.removeCallbacksAndMessages(null);
stopBLEScan();
super.onDestroy();
}
private void startBLEScan() {
bluetoothAdapter.startLeScan(BLECallback);
}
private void stopBLEScan() {
bluetoothAdapter.stopLeScan(BLECallback);
}
private void handleDiscoveredAsset(Asset asset) {
currentlyDiscoveredAssets.add(asset);
// Notify observers that we have a new asset discovered, but only if it was not
// discovered previously.
if (currentlyDiscoveredAssets.contains(asset) &&
!previouslyDiscoveredAssets.contains(asset)) {
notifyObserversOfNewAsset(asset);
}
}
private void performRepeatingTask() {
// Check if a previously discovered asset is not discovered this scan round,
// meaning it's not in range anymore.
for (Asset asset : previouslyDiscoveredAssets) {
if (!currentlyDiscoveredAssets.contains(asset)) {
notifyObserversOfLostAsset(asset);
}
}
// Update lists for a new round of scanning.
previouslyDiscoveredAssets.clear();
previouslyDiscoveredAssets.addAll(currentlyDiscoveredAssets);
currentlyDiscoveredAssets.clear();
// Reset the scan.
stopBLEScan();
startBLEScan();
}
private void notifyObserversOfNewAsset(Asset asset) {
Intent intent = new Intent();
intent.putExtra("macAddress", asset.MAC_address);
intent.setAction(EVENT_NEW_ASSET);
sendBroadcast(intent);
}
private void notifyObserversOfLostAsset(Asset asset) {
Intent intent = new Intent();
intent.putExtra("macAddress", asset.MAC_address);
intent.setAction(EVENT_LOST_ASSET);
sendBroadcast(intent);
}
}
This code is not perfect and might even be buggy, but it will at least give you an idea or example of how this can be implemented.
I can recommend this approach:
Use Map<BluetoothDevice, Long> structure to store the discovered devices, where Long is the time of detection of the device (can be System.currentTimeMillis() for example).
Then in your service (as far as I understand from the question there will be implemented some kind of repeated task) just extract actual devices based on the time of their detection.
And you are absolutely right, there are no guarantee that all nearby devices were discovered within the allotted time. Especially this is actual for the Android devices.
iOS devices in it's turn have another issue - they can change their BluetoothDevice's adress in runtime without apparent external cause.
Hope this will help you to save the time during debugging.
Edit
As a result of research of this topic found this discussion on code.google.com
Issue is still open and seems that it is related to the hardware features and can't be fixed programmatically. Moreover, it seems that bug will remains on problem devices even after a system updates.
So restarting the scan periodically might be acceptable workaround for this case.
My Question is: Can Android 4.3 (client) have active connections with multiple BLE devices (servers)? If so, how can I achieve it?
What I did so far
I try to evaluate what throughput you can achieve using BLE and Android 4.3 BLE API. In addition I also try to find out how many devices can be connected and active at the same time. I use a Nexus 7 (2013), Android 4.4 as master and TI CC2540 Keyfob as slaves.
I wrote a simple server software for the slaves, which transmits 10000 20Byte packets through BLE notifications. I based my Android App on the Application Accelerator from the Bluetooth SIG.
It works well for one device and I can achieve around 56 kBits payload throughput at a Connection Interval of 7.5 ms. To connect to multiple slaves I followed the advice of a Nordic Employee who wrote in the Nordic Developer Zone:
Yes it's possible to handle multiple slaves with a single app. You would need to handle each slave with one BluetoothGatt instance. You would also need specific BluetoothGattCallback for each slave you connect to.
So I tried that and it partly works. I can connect to multiple slaves. I can also register for notifications on multiple slaves. The problem begins when I start the test. I receive at first notifications from all slaves, but after a couple Connection Intervals just the notifications from one device come trough. After about 10 seconds the other slaves disconnect, because they seem to reach the connection time-out. Sometimes I receive right from the start of the test just notifications from one slave.
I also tried accessing the attribute over a read operation with the same result. After a couple of reads just the answers from one device came trough.
I am aware that there are a few similar questions on this forum: Does Android 4.3 support multiple BLE device connections?, Has native Android BLE GATT implementation synchronous nature? or Ble multiple connection. But none of this answers made it clear for me, if it is possible and how to do it.
I would be very grateful for advice.
I suspect everyone adding delays is just allowing the BLE system to complete the action you have asked before you submit another one. Android's BLE system has no form of queueing. If you do
BluetoothGatt g;
g.writeDescriptor(a);
g.writeDescriptor(b);
then the first write operation will immediately be overwritten with the second one. Yes it's really stupid and the documentation should probably actually mention this.
If you insert a wait, it allows the first operation to complete before doing the second. That is a huge ugly hack though. A better solution is to implement your own queue (like Google should have). Fortunately Nordic have released one for us.
https://github.com/NordicSemiconductor/puck-central-android/tree/master/PuckCentral/app/src/main/java/no/nordicsemi/puckcentral/bluetooth/gatt
Edit: By the way this is the universal behaviour for BLE APIs. WebBluetooth behaves the same way (but Javascript does make it easier to use), and I believe iOS's BLE API also behaves the same.
Re visting the bluetooth-lowenergy problem on android: I am still using delays.
The concept: after every major action that provokes the BluetoothGattCallback (e.g. conenction, service discovery, write, read) a dealy is needed. P.S. have a look at Google example on BLE API level 19 sample for connectivity to understand how Broadcasts should be sent and get some general understanding etc...
Firstly, scan (or scan) for BluetoothDevices, populate the connectionQueue with desired devices and call initConnection().
Have a look on the following example.
private Queue<BluetoothDevice> connectionQueue = new LinkedList<BluetoothDevice>();
public void initConnection(){
if(connectionThread == null){
connectionThread = new Thread(new Runnable() {
#Override
public void run() {
connectionLoop();
connectionThread.interrupt();
connectionThread = null;
}
});
connectionThread.start();
}
}
private void connectionLoop(){
while(!connectionQueue.isEmpty()){
connectionQueue.poll().connectGatt(context, false, bleInterface.mGattCallback);
try {
Thread.sleep(250);
} catch (InterruptedException e) {}
}
}
Now if all is good, you have made connections and BluetoothGattCallback.onConnectionStateChange(BluetoothGatt gatt, int status, int newState) has been called.
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
switch(status){
case BluetoothGatt.GATT_SUCCESS:
if (newState == BluetoothProfile.STATE_CONNECTED) {
broadcastUpdate(BluetoothConstants.ACTION_GATT_CONNECTED, gatt);
}else if(newState == BluetoothProfile.STATE_DISCONNECTED){
broadcastUpdate(BluetoothConstants.ACTION_GATT_DISCONNECTED, gatt);
}
break;
}
}
protected void broadcastUpdate(String action, BluetoothGatt gatt) {
final Intent intent = new Intent(action);
intent.putExtra(BluetoothConstants.EXTRA_MAC, gatt.getDevice().getAddress());
sendBroadcast(intent);
}
P.S. sendBroadcast(intent) might need to be done like this:
Context context = activity.getBaseContext();
context.sendBroadcast(intent);
Then the broadcast is received by BroadcastReceiver.onReceive(...)
public BroadcastReceiver myUpdateReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if(BluetoothConstants.ACTION_GATT_CONNECTED.equals(action)){
//Connection made, here you can make a decision: do you want to initiate service discovery.
// P.S. If you are working with multiple devices,
// make sure that you start the service discovery
// after all desired connections are made
}
....
}
}
After doing whatever you want in the broadcast receiver, here is how I continue:
private Queue<BluetoothGatt> serviceDiscoveryQueue = new LinkedList<BluetoothGatt>();
private void initServiceDiscovery(){
if(serviceDiscoveryThread == null){
serviceDiscoveryThread = new Thread(new Runnable() {
#Override
public void run() {
serviceDiscovery();
serviceDiscoveryThread.interrupt();
serviceDiscoveryThread = null;
}
});
serviceDiscoveryThread.start();
}
}
private void serviceDiscovery(){
while(!serviceDiscoveryQueue.isEmpty()){
serviceDiscoveryQueue.poll().discoverServices();
try {
Thread.sleep(250);
} catch (InterruptedException e){}
}
}
Again, after a successful service discovery, BluetoothGattCallback.onServicesDiscovered(...) is called. Again, I send an intent to the BroadcastReceiver (this time with different action String) and it is now that you can start reading, writing and enabling notifications/indications...
P.S. If you are working with multiple devices, make sure that you start the reading, writing etc... stuff after all devices have reported that their services have been discovered.
private Queue<BluetoothGattCharacteristic> characteristicReadQueue = new LinkedList<BluetoothGattCharacteristic>();
private void startThread(){
if(initialisationThread == null){
initialisationThread = new Thread(new Runnable() {
#Override
public void run() {
loopQueues();
initialisationThread.interrupt();
initialisationThread = null;
}
});
initialisationThread.start();
}
}
private void loopQueues() {
while(!characteristicReadQueue.isEmpty()){
readCharacteristic(characteristicReadQueue.poll());
try {
Thread.sleep(BluetoothConstants.DELAY);
} catch (InterruptedException e) {}
}
// A loop for starting indications and all other stuff goes here!
}
BluetoothGattCallback will have all your incoming data from the BLE sensor. A good practice is to send a broadcast with the data to your BroadcastReceiver and handle it over there.
I am developing an app with BLE features myself. The way I managed to connect to multiple devices and turn on notifications was to implement delays.
So I make a new thread (in order not to block UI thread) and in the new thread connect and turn on notifications.
For example, after BluetoothDevice.connectGatt(); call Thread.sleep();
And add the same delay for read/write and enable/dissable notifications.
EDIT
Use wait like this so that Android dindn't reaise ANR
public static boolean waitIdle() {
int i = 300;
i /= 10;
while (--i > 0) {
if (true)
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return i > 0;
}
Unfortunately notifications in the current Android BLE stack are a bit buggy. There are some hardcoded limits and I've found some stability issues even with a single device. (I read at one point that you could only have 4 notifications... not sure if that's across all devices or per device. Trying to find the source for that info now.)
I would try switching to a polling loop (say, poll the items in question 1/sec) and seeing if you find your stability increases. I would also consider switching to a different slave device (say a HRM or the TI SensorTag) to see if there is perhaps an issue with the slave-side code (unless you can test that against iOS or another platform and confirm it isn't part of the issue).
Edit: Reference for notification limitation
Rain is right in his answer, you need delays for pretty much everything when you work with BLE in Android. I developed several apps with it and it is really necessary. By using them you avoid a lot of crashes.
In my case, I use delays after every read/write command. Doing so, you ensure you receive the response from the BLE device almost always. I do something like this: (of course everything is done in a separate thread to avoid to much work on the main thread)
readCharacteristic(myChar);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
myChar.getValue();
or:
myChar.setValue(myByte);
writeCharacteristic(myChar);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
This is really useful when you read/write several characteristics in a row... As Android is enough fast to execute the commands almost instantly, if you don't use a delay between them you may get errors or incoherent values...
Hope it helps even if it is not exactly the answer to your question.