Android 10 released support for BLE CoC connection so I wanted to try this out by making two simple android 10 apps, which would connect to each other with l2Cap and exchange "Hello World".
I wrote two apps, Server app and Client app, both having all permissions they need in their manifest files, and I run that apps on two Android 10 phones, and the connection was not established.
Here is the relevant part of my server app code:
try {
mServerSocket = bluetoothAdapter.listenUsingInsecureL2capChannel();
int psm = mServerSocket.getPsm();
} catch (IOException e) {
e.printStackTrace();
}
BluetoothSocket socket = mmServerSocket.accept();
Variable int psm is the PSM value I am using in client app.
Here is the relevant part of my client app code:
for (BluetoothDevice bluetoothDevice : deviceSet) {
if (!bluetoothDevice.getName().equals(PAIRED_DEVICE_NAME)) continue;
BluetoothDevice bd = adapter.getRemoteDevice(bluetoothDevice.getAddress());
bluetoothSocket = bd.createInsecureL2capChannel(psm_value);
break;
}
bluetoothSocket.connect();
where the string PAIRED_DEVICE_NAME is name of expected device, which is successfully found because devices are Bluetooth paired.
Int psm_value is the PSM value from server app. I suspect this might be a problem because I hard-coded this value from Server every time I tried to test this (every time was different value because this value is dynamically assigned and it lasts until you close server socket).
So my question is how to get remote PSM value? And how to connect these devices, because if I am using RFCOMM connection, this code works perfectly.
With this code I am getting error in bluetoothSocket.connect() line from client app saying:
java.io.IOException: read failed, socket might closed or timeout, read ret: -1
Thanks!
Related
I noticed that the method onConnectionStateChange() is not invariably invoked (or just not invoked on time) when a peripheral is non-manually disconnected like for example when the peripheral is powered off. Is there a way to get the connection state of a connected BLE peripheral manually versus just waiting for the onConnectionStateChange() to fire? I tried using BluetoothManager#getConnectionState but this method seems to be accessing the connection state updated by whatever thread is calling onConnectionStateChange(), and does not actually ask the device if it's connected. In other words, BluetoothManager#getConnectionState just returns false if onConnectionStateChange() hasn't been called yet.
Here is my isConnected method
public boolean isConnected(){
// If the device has never connected, it's gatt service is null.
if(mGatt != null){
BluetoothManager btm =
(BluetoothManager)
MainActivity.mMainActivity.getSystemService(Context.BLUETOOTH_SERVICE);
int state = btm.getConnectionState(mGatt.getDevice(), BluetoothProfile.GATT);
return state == 2;
}
// The gat service is null, the device is not connected, return false.
return false;
}
onConnectionStateChange is being called as soon as the Bluetooth controller reports to the host Bluetooth stack that the link has been terminated. If you suddenly power off the peripheral without gracefully disconnecting, the connection will remain until the supervision timeout triggers. The default value of that was just changed from 20 seconds to 5 seconds in the latest Android versions because people have complained it was too long. The default on iOS is 0.72 seconds. On Android you can manually lower it by doing a connection parameter update request from the peripheral.
I have previously paired with a Bluetooth device that supports RFCOMM.
When my app is opened I continuously try to connect to the device by opening the RFCOMM. This way my app automatically connects when the device comes in range.
deviceInfoCollection = await DeviceInformation.FindAllAsync(RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort));
LogData(String.Format("Number of mldp devices is {0}", deviceInfoCollection.Count));
foreach (DeviceInformation deviceInfo in deviceInfoCollection)
{
LogData(String.Format("ID:{0}, NAME:{1}", deviceInfo.Id, deviceInfo.Name));
}
Then run this on a timer:
try
{
// The first time this method is invoked by a store app, it should be called
// from a UI thread in order to display the consent prompt
// https://msdn.microsoft.com/en-us/windows.devices.bluetooth.rfcomm.rfcommdeviceservice.fromidasync
RfcommDeviceService rfcommService = await RfcommDeviceService.FromIdAsync(deviceInfo.Id);
LogData(String.Format("ID:{0}, NAME:{1}", deviceInfo.Id, deviceInfo.Name));
}
catch (Exception)
{
LogData(String.Format("Can not request rfcomm service from device ID:{0}, NAME:{1}", deviceInfo.Id, deviceInfo.Name));
}
Is there any way to query when the device is in range , rather than trying to connect? I would prefer to only attempt connection when the device is in range.
For RFCOMM (BT2.0, BT2.1) you can run a device enumeration periodically, see also Get bluetooth devices in range
However your actual implementation with a connection attempt may work a little better.
For Bluetooth 4.0, you can listen to the advertisements of the BT module, see also https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/BluetoothAdvertisement
If you're talking to an embedded device (e.g. some robot, or homebrew appliances using RFCOMM) I am afraid there is no better solution than what you're doing.
If you're taking to a phone (which supports both BT4.0 and BT2.1) you can use the BT4 advertisements to signal the proximity of the device, then connect via RFCOMM.
I wanted to use Usage default app to determine how much data my own app send when in roaming mode.
I was very surprised to see that my device sent about 500 Mo. Then I realised that other apps on my phone should have used the network also.
So my question is: how can I enable roaming for just my app and prevent network access for everything else (updates, agenda, mail, ...)?
I run Firefox-OS 2.0 on a ZTE-Open device.
No, this is not possible.
The Data Usage App performs a test like this using the with the Network Stats API:
var end = new Date();
var start = new Date();
// Returns a mozNetworkStats object
var test = navigator.mozNetworkStats.getSamples('mobile', start, end);
console.log(test);
But this test will return a sample of all device connections, not only yours. The simplest solution is to measure the traffic in your Network Monitor.
However, if you want to reduce the amount of mobile traffic for your application, you can restrict all connections to specific connection types (like wifi). Just listen to the typechange event of the NetworkInformation.connection API.
In your WebIDE console (Firefox OS 2.0):
navigator.connection
NetworkInformation { type: "wifi", ontypechange: null }
or
navigator.connection
NetworkInformation { type: "cellular", ontypechange: null }
Please notice, that Firefox OS <=1.5 will never show you a cellular type of connection (it will return none if not wifi).
I wrote a Bluetooth client program for a wince 4.2 device. The device discovery works fine. However, when I attempt to connect to a PC, the connect function immediately returns with error code 10053. The connection request was being processed by the PC with a prompt to enter the authentication code but the wince device doesn’t seem to wait.
What could be causing this issue? I am using the following steps (removed error handling for simplicity):
WSAStartup(..)…////was successful.
SOCKET m_Socket =Socket (AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); //was successful.
SOCKADDR_BTH sClinet;
memset (&sClinet, 0, sizeof(sClinet));
sClinet.addressFamily = AF_BTH;
sClinet.btAddr = btd.btaddr; ; //BT_ADDR of the PC obtained via Device Discovery..
sClinet.port = BT_PORT_ANY; //I did try 0, did not help!
sClinet.serviceClassId = RFCOMM_PROTOCOL_UUID;
int nConErr = connect (m_Socket, (SOCKADDR *)&sClinet, sizeof(sClinet));
nConErr returns 10053 immediately. It doesn’t even wait, even though the PC recognized the connection and prompted a message to enter the PIN for authentication.
From what you are describing it looks like it is a pairing/authentication problem. You should consider in using also setsockopt function: http://msdn.microsoft.com/en-us/library/ms863347.aspx
You should try to use SO_BTH_AUTHENTICATE option which according to MSDN:
On connected socket, triggers authentication. On not connected socket, forces authentication on connection. For incoming connection this means that connection is rejected if authentication cannot be performed.
So before calling connect function you should set options to your socket.
If I have a Android phone which is already connected with a bluetooth headset (paired and connected) to it.
How I can get information about that specific headset.
Using getBondedDevices() method I get list of all paired devices..I need information about CONNECTED device only.
I can not wait for broadcast receiver to check status, because I need this information at the start of my application. So please suggest is there any way to get this information without waiting for broadcast.
You can do this through the IBluetoothA2dp interface in API 11 and up. Some more info on there is here: Android connect to a paired bluetooth headset
Here is a great resource to see the difference in what is available to this interface between API 10 and 11 where it changed quite a bit.
http://grepcode.com/file_/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/bluetooth/BluetoothA2dp.java/?v=diff&id2=2.2_r1.1
Hope that helps.
You can use the getConnectedDevices for the HEADSET Profile to get the device to which it is connected.
Check this out to see if headset is connected (ICS only):
public boolean isVoiceConnected()
{
boolean retval = true;
try {
retval = BluetoothAdapter.getDefaultAdapter().getProfileConnectionState(android.bluetooth.BluetoothProfile.HEADSET) != android.bluetooth.BluetoothProfile.STATE_DISCONNECTED;
} catch (Exception exc) {
// nothing to do
}
return retval;
}