getting STATE_DISCONNECTED while connecting using bluetooth smart - android

I am trying to create a advertiser on Android L and my other android device is scanning that device and trying to make a connection with it.
but every time i call connectGatt i am getting BluetoothProfile.STATE_DISCONNECTED in gatt callback.
this is how i have created the advertisement
// advertisement settings
AdvertiseSettings.Builder builderSetting= new AdvertiseSettings.Builder();
builderSetting.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED);
builderSetting.setConnectable(true);
builderSetting.setTimeout(0);
builderSetting.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);
//advertisement data
AdvertiseData.Builder builderData = new AdvertiseData.Builder();
builderData.addServiceUuid(new
ParcelUuid(UUID.fromString("00002a29-0000-1000-8000-00805f9b34fb")));
byte mServiceData[] =
{ (byte)0xff, (byte)0xfe, (byte)0x00, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04 };
// i tried with addding service data
builderData.addServiceData(new
ParcelUuid(UUID.fromString("00002a29-0000-1000-8000-00805f9b34fb")), mServiceData);
//start advertising
mBTAdvertiser.startAdvertising(
builderSetting.build(),
builderData.build(), mAdvCallback);

Since i can't comment yet ill try to make it an answer.
In your example i only see the Advertising enabled. However to offer GATT services, you also need to create a GATT-server which handles the requests.
Check out the documentation to BluetoothManager.openGattServer(...).
Good luck!

Related

Android BLE (Bluetooth Low Energy) Connect/Disconnect/Reconnect

The Android BLE API seems odd, maybe I'm missing something. What I need to do, is to make a connection to a BLE device, then if things are idle for a while disconnect temporarily, but when the user wants to do something new I want to reconnect.
To connect initially, I call:
Gatt1 = Device.ConnectGatt (Android.App.Application.Context, false, GattCallback);
Then I'm thinking to do my temporary disconnect I call
Gatt1.Disconnect();
And then when I want to re-connect, I call ConnectGatt() again, which gives me a new BluetoothGatt object:
Gatt2 = Device.ConnectGatt (Android.App.Application.Context, false, GattCallback);
So once I've called Gatt1.Disconnect(), I should just throw away Gatt1? It's not useful anymore, since when I re-connect I get a new BluetoothGatt object? Do I need to call some function to tell the API that I'm not using Gatt1 anymore?
(no, I wouldn't actually have two variables, Gatt1 and Gatt2, I'm just using those names to indicate there are two different objects happening)
When I eventually decided I'm completely done with this BLE device, I'm not planning on ever re-connecting, then I need to call Gatt.Close() (right?)
So maybe the code looks more like this?
BluetoothDevice Device = stuff();
BluetoothGatt Gatt = null;
if (connecting)
Gatt = Device.ConnectGatt(...);
else if (disconnecting temporarily)
Gatt.Disconnect();
else if (reconnecting after a temporary disconnection)
{
Gatt = null; // Yes? Do I need to specifically Dispose() this previous object?
Gatt = Device.ConnectGatt(...);
}
else if (disconnecting permanently)
{
Gatt.Close();
Gatt = null;
}
(again, no, I wouldn't write such a function, it's just to illustrate the lifespan of the various BluetoothGatt objects)
You need to also dispose the first BluetoothGatt object (Gatt1) when you are done with it, by calling the close() method on it. Just leaving the garbage collection to clean it up will not work I guess since it has no finalizer which calls the internal Bluetooth stack to clean it. If you don't close the object and just drop the reference, you will eventually run out of BluetoothGatt objects (there can be max 32 totally on the device for all apps together).
Gatt1 = Device.ConnectGatt (Android.App.Application.Context, false, GattCallback);
should be followed by:
Gatt1.connect();
Gatt1.disconnect() is correct for your purposes. When reconnecting, Gatt1 = null is unnecessary. Just call device.connectGatt() and Gatt1.connect() again. When you're completely done:
if(Gatt1!=null) {
Gatt1.disconnect();
Gatt1.close();
}
After reading these suggestions, and doing some more research, I think the answer is this:
BluetoothDevice Device = stuff();
BluetoothGatt Gatt = null;
if (connecting)
Gatt = Device.ConnectGatt(...);
else if (disconnecting temporarily)
Gatt.Disconnect();
else if (reconnecting after a temporary disconnection)
Gatt.Connect();
else if (disconnecting permanently)
{
Gatt.Disconnect();
Gatt.Close();
Gatt = null;
}
with a bunch of additional code to wait for the connect/disconnect actions to finish.

EADDRINUSE When creating server socket on google glass

I am developing a google glass/android application. It is a video streaming application that has a server/client setup where the phone/glasses is the server and hooks the pc up with the session description for playing the video. It works great on the android and everything runs fine but as soon as I try to test it on the google glass it throws an error at this line
sSocket = new ServerSocket(sPort);
The exception message says "EADDRINUSE" which I'm assuming means the port is already opened but I never opened it. Even if I had opened it and my program didn't close it I changed the port a couple of times and it still says it's in use.
Thanks
Tyler,
Google Glass, like android, consistently will have many of it's ports occupied by applications running in the background. When creating a socket for your server to listen on, you have two choices:
1) Have a predetermined list of ports you can choose to have your server listen on.
If you choose to do this, then you can simply have a datastructure (list, queue, heap [if you have some priority of which ports you would like to use], etc) which contain all of your ports, then you can simply traverse them until you find an open port.
This can be achieved in the following manner:
private ServerSocket allocatePort(List<Integer> myArray) throws IOException {
for (int individualPort : myArray) {
try {
return new ServerSocket(individualPort);
} catch (IOException io) {
continue; // An exception will be thrown if this port is currently in use. It's OK, let's try another port.
}
}
// When no ports are available, let's throw an exception stating we were unable to find an open port.
throw new IOException("we were unable to find an open port");
}
Then simply invoke this method within your as follows:
int[] arrayOfPorts = {5000, 5001, 5002, 8000, 8001, 8002, 8003};
List<Integer> myArray = new ArrayList<>();
myArray = IntStream.of(arrayOfPorts).boxed().collect(Collectors.toList());
ServerSocket sSocket = allocatePort(myArray);
2) If you don't mind which port to listen in on, you can use the constructor to pick any available port.
This can be achieved as follows:
ServerSocket sSocket = new ServerSocket(0);
You can read up more on ServerSocket's Javadocs. Notice under the parameter's subsection:
port - the port number, or 0 to use a port number that is automatically allocated.
Please let me know if you have any questions!

Android IsoDep command chaining failure

I am making a NFC application that use ISO-DEP (ISO 14443-4) as TagTechnology.
I try to execute a authentication with a DESFire EV1.
The authentication work well if the chaining of the command is without pause.
But if for exemple, I make something that take time (like the Thread.Sleep after NATIVE_AUTHENTICATION_COMMAND_P1) I got an error 0x911C ("Command code not supported") during the authentication command part 2 from the card.
Normaly the error come when the authentication has been canceled. Like if the card got another command during the authentication procedure that have nothing about it.
The problem is that my application do nothing else that sending the selectApplication, Authentication Part 1, Sleep and the Part 2.
I have try the same code in C++ with a PCSC Reader and the Sleep is not the probleme, even with 5 second sleep the authentication have work on my computer.
So I would like to know if Android is "playing" with the card even after giving the Intent to the application or if the Frame Waiting Time (ISO 14443-4) is not working or NDEF "pull" broke the authentication or...
(The value of NATIVE_AUTHENTICATION_COMMAND_P2 is a exemple)
final byte[] NATIVE_AUTHENTICATION_COMMAND_P1 = new byte[]{(byte)0x90, (byte)0x0A, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x00};
final byte[] NATIVE_AUTHENTICATION_COMMAND_P2 = new byte[]{(byte)0x90, (byte)0xAF, (byte)0x00, (byte)0x00, (byte)0x10, (byte)0xAB, (byte)0xB4, (byte)0x66, (byte)0xA4, (byte)0xE9, (byte)0x99, (byte)0xFF, (byte)0x5C, (byte)0xD7, (byte)0xF3, (byte)0xA7, (byte)0x81, (byte)0x62, (byte)0x2F, (byte)0xFA, (byte)0x16, (byte)0x00};
final byte[] NATIVE_SELECT_COMMAND = new byte[]{(byte)0x90,(byte)0x5A,(byte)0x00,(byte)0x00,(byte)0x03,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00};
IsoDep tag = IsoDep.get(tagFromIntent);
tag.connect();
byte[] result;
result = tag.transceive(NATIVE_SELECT_COMMAND); //SUCCESS
result = tag.transceive(NATIVE_AUTHENTICATION_COMMAND_P1); //SUCCESS
// Thread.sleep(1000);
result = tag.transceive(NATIVE_AUTHENTICATION_COMMAND_P2); //result = 0x90AE without Sleep and with Sleep 0x911C ("Command code not supported")
tag.close();
If someone have an idea because I am totally lost :)
UPDATE:
After the help of michael-roland and his tips; I have use the reader-mode API with NDEF check disable and delay presence check to 10 second to get my chaining command working perfectly !
#Override
protected void onResume() {
super.onResume();
Bundle options = new Bundle();
options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 10000);
mAdapter.enableReaderMode(this, this, NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, options);
}
#Override
public void onPause() {
super.onPause();
mAdapter.disableReaderMode(this);
}
You ran into a known problem with the NFC stack for Broadcom's NFC chipset. The issue is known for quite a while (see this Android bug report, something similar applies to non APDU-based tags too).
In your case, the problem is that while the connection between the phone and the tag is idle, Android automatically performs a presence check. While this presence check is correctly implemented for NXP's NFC stack, the Broadcom version uses a READ BINARY command (for IsoDep cards) or an equivalent READ command (for other tag technologies).
So, if your command sequence is slow, Android might send a READ BINARY APDU somewhere in between your commands.
Unfortunately, this bug still exists in Android 4.4.2 and to me it seems unclear if Google will eventually do something about it. UPDATE: There is a new presence check mechanism starting with Android 5.
If you use Android 4.4, there is, however, something you can do to avoid the bug: Use the new reader-mode API to tweak the presence-check timeout. If you do not use NDEF, you could even completely disable the presence-check.

createRfcommSocketToServiceRecord works but listenUsingRfcommWithServiceRecord does not

I am trying to control a Hands-Free link with my device. The following works just fine:
UUID HFP_UUID_GET_HF = UUID.fromString("0000111E-0000-1000-8000-00805F9B34FB");
BluetoothSocket aBluetoothSocket = mDevice
.createRfcommSocketToServiceRecord(HFP_UUID_GET_HF);
and I get a socket that I can read and right to. No problem. However, I also want to listen for an incoming connection and get that socket. I tried this:
UUID HFP_UUID = UUID.fromString("0000111F-0000-1000-8000-00805F9B34FB");
UUID HFP_UUID_GET_HF = UUID.fromString("0000111E-0000-1000-8000-00805F9B34FB");
BluetoothServerSocket tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("HFP", HFP_UUID);
BluetoothSocket aBluetoothSocket = tmp.accept();
However, even though the two devices connect I never get a socket back. BTW if I use the UUID that starts with 111E in this second code block here I get a service discovery io error, which makes sense -- I know that my device is using uuid 111F and the other device uses UUID 111E.
Has anyone ran into this issue before? I need to be able to have complete control over all data that gets sent from the phone on that rfcomm channel. I cannot use reflection ; i.e.
Class<?>[] args = new Class[] { int.class };
int HFP_CHANNEL = 10;
Method listenOn = BluetoothAdapter.class.getDeclaredMethod("listenUsingRfcommOn", args);
BluetoothServerSocket my_server = (BluetoothServerSocket) (listenOn.invoke(mBluetoothAdapter,
new Object[] { HFP_CHANNEL }));
BluetoothSocket m_BluetoothSocket = my_server.accept();
because that also throws an io error -- channel already in use, unless anyone knows a way to turn off the hands-free system service. Afaik that is part of bluetoothd (Im using Android 4.1 here) and I need that to remain running (Im not sure if I even can turn it off)

How do I get the UUID of a bluetooth device?

I need to know UUID on API 8 (2.2) or possibly 2.3.3.
As I understand the documentation, this should be allowed:
phoneDevice = blueAdapter.getRemoteDevice(phoneAddress);
ParcelUuid[] phoneUuids = phoneDevice.getUuids(); // Won't compile
Eclipse gives me:
"The method getUuids() is undefined for the type BluetoothDevice."
But see:
http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getUuids()
Also, I would like to know how the UUIDs are "parceled" inside the ParcelUuid[]. In case I ever manage to get there, how do I retrieve a UUID from a parcelUuid[]? Documentation for Android bluetooth seems to be very poor, in my opinion.
What a joke!
Now I try to get it from the intent, but this too gives: *"EXTRA_UUID cannot be resolved or is not a field"*:
intent.getParcelableExtra(BluetoothDevice.EXTRA_UUID);
You have to use reflection to use the getUuids() and fetchUuidsWithSdp() on android version < 3. So, try the code:
Method method = phoneDevice.getClass().getMethod("getUuids", null);
ParcelUuid[] phoneUuids = (ParcelUuid[]) method.invoke(phoneDevice, null);
//this will support from API level 15 and above.
Broadcast Action: This intent is used to broadcast the UUID wrapped as a ParcelUuid of the remote device after it has been fetched. This intent is sent only when the UUIDs of the remote device are requested to be fetched using Service Discovery Protocol
Always contains the extra field EXTRA_DEVICE
Always contains the extra field EXTRA_UUID
Requires BLUETOOTH to receive.
Constant Value: "android.bluetooth.device.action.UUID"
//no way to degrade its hardware related. there is no supporting jar also. http://developer.android.com/sdk/compatibility-library.html
Unfortunately, I don't think there is any good way to get the UUID's supported by a BluetoothDevice with API level < 15. I guess that's why they added the new functions in API 15.
Note, from the docs for BluetoothClass
BluetoothClass is useful as a hint to roughly describe a device (for
example to show an icon in the UI), but does not reliably describe
which Bluetooth profiles or services are actually supported by a
device. Accurate service discovery is done through SDP requests, which
are automatically performed when creating an RFCOMM socket with
createRfcommSocketToServiceRecord(UUID) and
listenUsingRfcommWithServiceRecord(String, UUID).
So, perhaps the device class could be used as a hint as to what services will be available until you perform one of the listed functions. Certainly it doesn't hurt to check the class since this won't require any additional bluetooth operations.
Note that the service class is also available (it is part of the device class) but this is just a general class, not a listing of specific services (like from SDP).
try BluetoothAdapter class
any question, read: http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html
In case you can not get UUID from getUuids() method. Please try the other way.
After scanned successfully, you should receive byte[] (scanRecord), so from this result, if you can recognize UUID format you can split step by step to get correct UUID as these codes.
P/s : Important thing, you should know UUID format to get from index correctly.
// Put item into hash map
// UUID from index 10 to 24 : 12233445566778899aabbccddeeff0
StringBuilder mSbUUID = new StringBuilder();
for (int i = 0; i < scanRecord.length; i++) {
// UUID
if (i >= 10 & i <= 24) {
if (Integer.toHexString(
scanRecord[i]).contains("ffffff")) {
mSbUUID.append(Integer.toHexString(scanRecord[i]).replace("ffffff", "") + "-");
} else {
mSbUUID.append(Integer.toHexString(scanRecord[i]) + "-");
}
}
}

Categories

Resources