Android BLE scan and show of result - android

I'm developing an android app that needs to connect to a Bluetooth-low-energy device. In order of achieving that goal, and following the Android Dev page, I have included the correct permissions in the manifest file. In the mainActivity I'm trying to scan for BLE devices and printing the result on the screen. The code looks like this:
final BluetoothLeScanner bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
bluetoothLeScanner.startScan(callback);
// Before 5 seconds, stop the scan and show results.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
bluetoothLeScanner.stopScan(callback);
callback.onBatchScanResults(results);
callback.onScanFailed(2);
callback.onScanResult(3,result);
listOfResults.setText(results.toString());
}
},5000);
Where:
bluetoothApater is the BlueoothAdapter needed to perform the operation as it's told in the android page,
bluetoothLeScanner is the object needed to perform LE scan operations,
callback is a Scan call back object,
results is a List < ScanResult >
result is a ScanResult,
and listOfResults is text view.
The problem maybe is in the method used, because according to the Android Official Page, we find three voids to perform with a callback (onBatchScanResult, onScanResult, and onScanFailed), but I only get working onBatchScanResult.
Why no device is shown? The only thing printed is the name of the activity, the name of the package and the app name.

The way I did it was to implement scanCallback() object and overriding the onScanResult() or onBatchScanResults() as needed.
private ScanCallback callback= new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
// handles scan result
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
// handles batch scan results
for (ScanResult result : results) {
// you can iterate through each result like so
}
}
#Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
// handles error
}
};
You then pass callback inside of stopScan() and startScan()
bluetoothLeScanner.startScan(callback);
bluetoothLeScanner.stopScan(callback);
Also consider using result.getDevice() so you can retrieve the specific data of the device you need instead of a large chunk of information. For example, result.getDevice().getAddress() if you want the address only.

Have you added location permissions in manifest and also check if location permission is granted at runtime? If you havent done this, your results will always be null.

Related

How to filter BLE devices that are advertising extended advertising message?

I have implemented the following BLE scan callback,
private final ScanCallback mScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
Log.d(TAG,"onScanResult: " +result.toString());
runOnUiThread(() -> {
if (result.getDevice().getName() != null && getString(R.string.unknown_device_text).compareTo(result.getDevice().getName().toLowerCase()) != 0) {
mLeDeviceListAdapter.addDevice(result.getDevice());
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
super.onScanResult(callbackType, result);
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
Log.d(TAG,"onBatchScanResults: " +results.toString());
super.onBatchScanResults(results);
}
#Override
public void onScanFailed(int errorCode) {
Log.d(TAG,"onScanFailed: errorCode: " +errorCode);
super.onScanFailed(errorCode);
}
};
However, in this callback I am not getting BLE devices that are advertising extended message. In contrast, in same place nRF app shows extended devices in their list.
Here is my scan method,
private void scanLeDevice() {
List<ScanFilter> filters = new ArrayList<>();
ScanFilter.Builder scanFilterBuilder = new ScanFilter.Builder();
filters.add(scanFilterBuilder.build());
ScanSettings.Builder settingsBuilder = new ScanSettings.Builder();
settingsBuilder.setPhy(ScanSettings.PHY_LE_ALL_SUPPORTED);
final BluetoothLeScanner bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
bluetoothLeScanner.stopScan(mScanCallback);
Log.d(TAG, "scanLeDevice stopScan called");
}
}, SCAN_PERIOD);
bluetoothLeScanner.startScan(filters, settingsBuilder.build(), mScanCallback);
}
So, how can I filter and find the devices with extended advertising capabilities.
In order to show extended advertisements, you need to use the setLegacy(false) method. By default this is set to true, which is why you need to change it when setting up your scan settings.
Have a look at the links below for more information:-
ScanSettings.Builder setLegacy
How to scan Bluetooth 5 extended advertising with Pixel 3a
UPDATE
You can filter only BLE devices that are doing extended adverts by checking the advert type. You can access the advert type by reading the scanRecord (e.g. using the getBytes method). You can read further on how to read the advert type here and here. Legacy adverts will be one of the following 4 types:-
ADV_IND
ADV_DIRECT_IND
ADV_NONCONN_IND
ADV_SCAN_IND
While extended adverts will be one of the following 4 types:
ADV_EXT_IND
AUX_ADV_IND
AUX_SYNC_IND
AUX_CHAIN_IND
This can be see in more details in the table below:-
Below are some other useful links on understanding the meaning of advert packets:-
Bluetooth 5 adverts: Everything you need to know
How do iBeacons work
BLE advertising primer

Android BLE - Connecting to multiple devices at once

I am developing an Android Application that connects to a BLE Device and reads the Gatt Services and Gatt Characteristics. I used the BluetoothLeGatt sample project from the Android Development Site as my reference.
So far, I am able to programmatically connect to a device (I took note of my Device's Address to be able to do this) and filter out the specific Gatt Service I want to read and that Services' specific Characteristics by taking note of the UUID of both the Service and the Characteristics. The sample provided by Google also updates whenever there's a message sent from my BLE Device to my Android Application. Overall, I have no problems at this end.
However, upon reading up further on GATT, I found that it is possible to connect to multiple BLE devices (all slaves OR servers - being the ones that send the data) using a single Android Application (as master OR client - as the one who receives said data). So what I tried to do was to have 2 BLE Devices (different Address), took note of their Address, and then my application tries to connect to them once the application sees that those 2 addresses are up and running.
In code, I call this function when I see my 2 BLE Devices:
private void connectToDevice(){
mDeviceName = deviceList.get(currentIndex).getName();
mDeviceAddress = deviceList.get(currentIndex).getAddress();
Log.e(TAG, "connecting to device name = " + mDeviceName);
mBluetoothLeService.connect(mDeviceAddress);
}
Where currentIndex is initially set to zero. Then once I get a successful connection, I do:
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, "connected");
mConnected = true;
if(currentIndex < deviceList.size()-1) currentIndex ++;
connectToDevice();
}
}
};
Where I check if I still have devices to connect to in my deviceList, if so, increment my counter and then connect until I exhaust everything in my list.
However, I seem to have no success at all using this method.
Kindly note that switching connection (round robin) between my devices isn't an option. This will be an issue when I have a lot of devices and it's important to get their messages real time without delays. This said, I have to have a live connection to my devices.
Has anyone tried to connect to multiple BLE Devices in Android? I'm not sure on how to proceed on this.
Indeed it is possible to connect to more than one peripheral from your Android device. However, it will make your code much more complex since you will need to manage each connection and responses.
For each connection you would have to implement a BluetoothGatt with it's callbacks. I tested it many months ago with a dummy test and as I said, it worked well and I was able to connect to different peripherals. However, if you chain many commands there seem to be some overlapping issues described in this thread.
As asked here is the relevant code : (Here the ArrayList contains the founded peripheral devices)
for(int i=0;i< Utility.selectedDeviceList.size();i++) {
Log.d(Utility.TAG,"state"+ Utility.selectedDeviceList.get(i).getmConnectionState());
if (Utility.selectedDeviceList.get(i).getmConnectionState() != Utility.CONNECTED) {
Log.d(Utility.TAG,"Connecting LeSerive::" + Utility.selectedDeviceList.get(i).getAddress());
Utility.mBluetoothLeService.connect(i, Utility.selectedDeviceList.get(i).getAddress());
}
}
This for loop is a part of runnable interface which is called inside a handler having a looper.
public void run() {
Looper.prepare();
Looper mLooper = Looper.myLooper();
Log.d(Utility.TAG,"BLE Thread Started::");
mHandler = new Handler(mLooper) {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Utility.BLE_SYNC:
Log.d(Utility.TAG,"BLE Sync Connecting::");
mHandler.post(SynState);
break;
}
};
Looper.loop();
}
I used this approach because their is lot of communication between peripherals to send and receive the data from them.
This is the connect method which inside a Service :
public boolean connect(int tag,final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(Utility.TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
Utility.selectedDeviceList.get(tag).setmConnectionState(Utility.CONNECTING);
if( Utility.selectedDeviceList.get(tag).getmBluetoothGatt()==null){
Log.w(Utility.TAG, "new connect :: "+ Utility.selectedDeviceList.get(tag).getAddress());
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(Utility.TAG, "Device not found. Unable to connect.");
return false;
}
try {
Utility.selectedDeviceList.get(tag).setmBluetoothGatt(device.connectGatt(this, false, mGattCallback));
}
catch (Exception e)
{
e.printStackTrace();
Log.d(Utility.TAG,"ConnectGatt exception caught");
}
}
return true;
}
This is the mGattCallBack :
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
Log.d(Utility.TAG, "onServicesDiscovered");
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic,int status) {
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
Log.d(Utility.TAG,">>onCharacteristicWrite");
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic) {
}
};
Hope it clears few things for you
It is possible to connect to multiple devices at a time. in my experience it works pretty stable and the number of devices you can connect to (stable) depends on your hardware. I found out that best practise (for me) was to create one separate service for the scanning stuff and one service for each Bluetoothconnection. it's important not to use bound services because the termination of a connection is not stible when binding to it.
With this pattern you can control your connection easily. To transport data out of your service you can use a broadcastreceiver, for example if you want to display the data in your main activity. Termination of the connection is pretty important so stop the service and in onDestroy call
mConnectedGatt.disconnect();
ble_device=null;
For the Scanning part I've used a List of Strings where I saved all the mac Adresses I want to find. When i found one device I deleted it from the list and if the list is empty it stopped the scanner service. To transmit my found device I used a broadcastreceiver and sent it to my main Activity. There I transmitted it to the right service.
Hope this helps

Android BLE setReportDelay()

I'm trying to implement a BLE scan app where i want to list all the devices nearby in a single scan rather than getting one BLE device at a time.
I read from the Android Documentation that i can use setReportDelay() in the Scan Setting Builder to delay the scan results and to use the BatchScanResults() to get a batch/list of devices found.
However when i try to use the setReportDelay() in the Scan Settings builder the scan does not start at all and i get the following error.
04-13 16:03:19.887 8454-8454/com.example.sasnee_lab2.sasbeacon D/BluetoothLeScanner﹕ could not find callback wrapper
Here is my StartScan function with Scan Settings
public void startScan(BluetoothLeScanner scanner)
{
ScanFilter filter = new ScanFilter.Builder().setDeviceName(null).build();
ArrayList<ScanFilter> filters = new ArrayList<ScanFilter>();
filters.add(filter);
ScanSettings settings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_POWER).setReportDelay(1l)
.build();
Log.i(TAG,"The setting are "+settings.getReportDelayMillis());
scanner.startScan(filters,settings,BLEScan);
}
And here is the Scan Callback.
private ScanCallback BLEScan = new ScanCallback() {
#Override
public void onBatchScanResults(List<ScanResult> results) {
Log.i(TAG,"The batch result is "+results.size());
}
#Override
public void onScanResult(int callbackType, ScanResult result) {
Log.i(TAG,"******************************************");
Log.i(TAG,"The scan result "+result);
Log.i(TAG,"------------------------------------------");
}
#Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
}
}
};
Please let me know if i'm doing anything wrong in the implementation here.
And thank you.
You must check whether your hardware supports scan batching through BluetoothAdapter.isOffloadedScanBatchingSupported(). If this returns false then you should not attempt to set a report delay.
Use this:
Java
boolean f = adapter.isOffloadedScanBatchingSupported();
if (!f) builder.setReportDelay(0) else builder.setReportDelay(1)
Kotlin
val f: Boolean = adapter.isOffloadedScanBatchingSupported
if (!f) builder.setReportDelay(0) else builder.setReportDelay(1)

Wifi P2P service discovery works intermittently

Wifi P2P service discovery is not behaving as expected. I am seeing intermittent issues where the DNSSD listeners are not called always and hence I have no clue of nearby devices running the same app. I am using the following two APIs - one to register a service to be discovered by other devices and the other to discover the nearby services running on other devices. Any idea if I am doing anything wrong here or is there some specific sequence of other android API calls that need to be made before I call these APIs to ensure that the listeners are always called whenever there is a new service registered or even if a service is registered before we call the API to discover the local services.
API to register a local service:
private void registerService() {
Map<String, String> values = new HashMap<String, String>();
values.put("name", "Steve");
values.put("port", "8080");
WifiP2pServiceInfo srvcInfo = WifiP2pDnsSdServiceInfo.newInstance(mMyDevice.deviceName, "_http._tcp", values);
manager.addLocalService(channel, srvcInfo, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Toast.makeText(WiFiDirectActivity.this, "Local service added successfully",
Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(int reasonCode) {
Toast.makeText(WiFiDirectActivity.this, "Local service addition failed : " + reasonCode,
Toast.LENGTH_SHORT).show();
}
});
}
API to discover local services:
public void discoverService() {
manager.clearServiceRequests(channel, null);
DnsSdTxtRecordListener txtListener = new DnsSdTxtRecordListener() {
#Override
/* Callback includes:
* fullDomain: full domain name: e.g "printer._ipp._tcp.local."
* record: TXT record data as a map of key/value pairs.
* device: The device running the advertised service.
*/
public void onDnsSdTxtRecordAvailable(String fullDomain, Map record, WifiP2pDevice device) {
Log.d(TAG, "DnsSdTxtRecord available -" + record.toString());
}
};
DnsSdServiceResponseListener servListener = new DnsSdServiceResponseListener() {
#Override
public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice resourceType) {
Log.d(TAG, "onBonjourServiceAvailable " + instanceName);
}
};
manager.setDnsSdResponseListeners(channel, servListener, txtListener);
WifiP2pDnsSdServiceRequest serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
manager.addServiceRequest(channel, serviceRequest, new ActionListener() {
#Override
public void onSuccess() {
// Success!
Log.d(TAG, "addServiceRequest success");
}
#Override
public void onFailure(int code) {
// Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY
Log.d(TAG, "addServiceRequest failure with code " + code);
}
});
manager.discoverServices(channel, new ActionListener() {
#Override
public void onSuccess() {
// Success!
Log.d(TAG, "discoverServices success");
}
#Override
public void onFailure(int code) {
// Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY
if (code == WifiP2pManager.P2P_UNSUPPORTED) {
Log.d(TAG, "P2P isn't supported on this device.");
} else {
Log.d(TAG, "discoverServices failure");
}
}
});
}
Note: manager & channel are initialized as
WifiP2pManager manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
Channel channel = manager.initialize(this, getMainLooper(), null);
WifiP2p (in general):
Some time ago I was developing an application with a pretty complex network connectivity system based on WifiP2p with Service Broadcasting/Discovery. And based on that experience I already wrote few posts here on SO about how difficult, wearing and problematic that is. Here are two of them (they are quite full of the inside knowledge I acquired about WifiP2p with Service Discovery, and WifiP2p itself):
Why is discovering peers for Android WifiDirect so unreliable
Wi-fi P2P. Inform all peers available of some event
I would advise you to read both of my answers (even though they are focused a bit more on the WifiP2p itself). They should give you some perspective on the things you should be looking for when working with the WifiP2p Service Discovery.
I can easily say that if you want to build an efficient, relatively reliable and robust WifiP2p connection system (especially with Service Discovery), you will have to work your ass off.
WifiP2p Service Discovery:
To better answer your exact question, I will tell you what I did (different from you) to make my Service Discovery work pretty reliably.
1. Broadcasting Service:
First of all: before registering your Service (with addLocalService method) you should use the WifiP2pManager's clearLocalServices method. And it is important, that you should only call addLocalService if the listener passed in the clearLocalServices returned with the onSuccess callback.
Although this sets up the broadcasting pretty nicely, I found that other nodes were not always able to detect the broadcasted service (especially when those nodes weren't already actively detecting services at the moment of registering your local Service - but they "joined" later). I couldn't find a way to fix this issue 100% reliably. And believe me I was trying probably everything WifiP2p-related. And no, the clearLocalServices-addLocalService sequence wasn't really giving satisfying results. Or more so: doing something different was working much better. What I decided to do, was after I successfully added local service (onSuccess callback from addLocalService), I started a Thread that would periodically call WifiP2pManager's method discoverPeers. That seemed to be forcing to rebroadcast all the service information.
So... basically the base of your broadcasting code should look more-less like this (bare in mind that every single piece of code I will post here is stripped-off of all "checks" if the network connectivity system is in the right state, you should design them yourself to fit your solution the best):
public void startBroadcastingService(){
mWifiP2pManager.clearLocalServices(mWifiP2pChannel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
mWifiP2pManager.addLocalService(mWifiP2pChannel, mWifiP2pServiceInfo,
new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
// service broadcasting started
mServiceBroadcastingHandler
.postDelayed(mServiceBroadcastingRunnable,
SERVICE_BROADCASTING_INTERVAL);
}
#Override
public void onFailure(int error) {
// react to failure of adding the local service
}
});
}
#Override
public void onFailure(int error) {
// react to failure of clearing the local services
}
});
}
where the mServiceBroadcastingRunnable should be:
private Runnable mServiceBroadcastingRunnable = new Runnable() {
#Override
public void run() {
mWifiP2pManager.discoverPeers(mWifiP2pChannel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
}
#Override
public void onFailure(int error) {
}
});
mServiceBroadcastingHandler
.postDelayed(mServiceBroadcastingRunnable, SERVICE_BROADCASTING_INTERVAL);
}
};
2. Discovering Service:
For the discovering of your service I used similar approach. Both with the setting up the discovering, and with trying to force "rediscovery" of services.
Setting up was performed with the sequence of the following three WifiP2pManager's methods:
removeServiceRequest, addServiceRequest, discoverServices
They were called in this exact order and a particular method (second or the third one to be exact) has been called only after the previous one had "returned" with the onSuccess callback.
The rediscovery of services was being performed with the intuitive method (just by repeating the mentioned sequence: removeServiceRequest -> addServiceRequest -> discoverServices).
The base of my code looked more-less like this (to start Service Discovery I would first call prepareServiceDiscovery() and then startServiceDiscovery()):
public void prepareServiceDiscovery() {
mWifiP2pManager.setDnsSdResponseListeners(mWifiP2pChannel,
new WifiP2pManager.DnsSdServiceResponseListener() {
#Override
public void onDnsSdServiceAvailable(String instanceName,
String registrationType, WifiP2pDevice srcDevice) {
// do all the things you need to do with detected service
}
}, new WifiP2pManager.DnsSdTxtRecordListener() {
#Override
public void onDnsSdTxtRecordAvailable(
String fullDomainName, Map<String, String> record,
WifiP2pDevice device) {
// do all the things you need to do with detailed information about detected service
}
});
mWifiP2pServiceRequest = WifiP2pDnsSdServiceRequest.newInstance();
}
private void startServiceDiscovery() {
mWifiP2pManager.removeServiceRequest(mWifiP2pChannel, mWifiP2pServiceRequest,
new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
mWifiP2pManager.addServiceRequest(mWifiP2pChannel, mWifiP2pServiceRequest,
new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
mWifiP2pManager.discoverServices(mWifiP2pChannel,
new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
//service discovery started
mServiceDiscoveringHandler.postDelayed(
mServiceDiscoveringRunnable,
SERVICE_DISCOVERING_INTERVAL);
}
#Override
public void onFailure(int error) {
// react to failure of starting service discovery
}
});
}
#Override
public void onFailure(int error) {
// react to failure of adding service request
}
});
}
#Override
public void onFailure(int reason) {
// react to failure of removing service request
}
});
}
the mServiceDiscoveringRunnable was just:
private Runnable mServiceDiscoveringRunnable = new Runnable() {
#Override
public void run() {
startServiceDiscovery();
}
};
All this made my system work quite well. It wasn't perfect yet, but with the lack of documentation on this subject I think I couldn't do much more to improve it.
If you test this approach, be sure to tell me how it works for you (or if it works for you ;) ).
if the problem is the detection of the service i believe that crearing group is the best way to make the device and service detectable but the if created group in the all devices then you cannot connect in direct.
but as wifi network.
i do it every day and it works.

Unable to both start and discover a specific service with Wifi Direct

I'm pretty new with Android programming. But I have been working on this for over a week now, and it starts to get booooring.
My idea is that I want to connect two devices using Wifi Direct. But I only want to connect to those which are running my application. Besides, I want the users to be able to see some information of the other devices (such as user name), not just the MAC or the Android_XXXX name included in the WifiP2pDevice. That's why I decided that a device looking for other devices, should both start the application service and search for peers which are also broadcasting this service.
The problem (I'm testing with two real devices) is that, even though they are running exactly the same code, only one of them is getting the service discovery callbacks (the onDnsSd... listeners below). So, one side acts in the proper way, but not the other. Moreover I'm getting "old" services, meaning that apparently each time I start de service (even though I cancel previously started services), that service seems to be still broadcast during at least some minutes.
I include a shortened version of my code:
public class MoveFlufietsDialogFragment extends DialogFragment implements ChannelListener, DeviceActionListener {
public final HashMap<String, FlufietsPeer> mBuddies = new HashMap<String, FlufietsPeer>();
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
...
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
mManager = (WifiP2pManager) getActivity().getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mManager.initialize(getActivity(), getActivity().getMainLooper(), null);
...
startRegistration();
discoverFlufietsService();
...
}
public void discoverFlufietsService() {
DnsSdTxtRecordListener txtListener = new DnsSdTxtRecordListener() {
#Override
public void onDnsSdTxtRecordAvailable(String fullDomain, Map record, WifiP2pDevice device) {
// This and the next listener are only called in one of the devices.
String serviceName = (String) record.get("serviceName");
if ((serviceName != null) && (serviceName.equals("flufiets")) {
// I put the record data in the mBuddies HashMap.
...
mBuddies.put(device.deviceAddress, myPeerDataStructure);
}
}
};
DnsSdServiceResponseListener servListener = new DnsSdServiceResponseListener() {
#Override
public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice resourceType) {
if (mBuddies.containsKey(resourceType.deviceAddress)) {
FlufietsPeer flufietsPeer = mBuddies.get(resourceType.deviceAddress);
WiFiPeerListAdapter adapter = ((WiFiPeerListAdapter) mFragmentList.getListAdapter());
adapter.add(flufietsPeer);
adapter.notifyDataSetChanged();
}
}
};
mManager.setDnsSdResponseListeners(mChannel, servListener, txtListener);
WifiP2pDnsSdServiceRequest serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
mManager.addServiceRequest(mChannel, serviceRequest, new ActionListener() {
// onSuccess/onFailure toasts.
});
mManager.discoverServices(mChannel, new WifiP2pManager.ActionListener() {
// onSuccess/onFailure toasts.
});
}
public void startRegistration() {
mManager.clearLocalServices(mChannel, new ActionListener() {
// onSuccess/onFailure toasts.
});
Map record = new HashMap();
record.put("serviceName", "flufiets");
...
WifiP2pDnsSdServiceInfo serviceInfo = WifiP2pDnsSdServiceInfo.newInstance(flufietsService, "_tcp", record);
mManager.addLocalService(mChannel, serviceInfo, new ActionListener() {
// onSuccess/onFailure toasts.
});
}
#Override
public void onResume() {
super.onResume();
mReceiver = new WiFiDirectBroadcastReceiver(mManager, mChannel, this);
getActivity().registerReceiver(mReceiver, mIntentFilter);
}
#Override
public void onPause() {
super.onPause();
getActivity().unregisterReceiver(mReceiver);
}
#Override
public void onStop() {
super.onStop();
mManager.clearLocalServices(mChannel, new ActionListener() {
// onSuccess/onFailure toasts.
});
}
...
}
The problem doesn't seem to be related with the device itself (sometimes it works, sometimes it doesn't, but always only in one of them). I suspect it has to do with either trying to discover a service that we ourselves are broadcasting, or having the same service being offered by two devices. I have tried changing the names of the service, so each device would offer either a "send" or "receive" service, but it doesn't work. I only get the callbacks called (onDnsSd...) in one of the devices.
And that thing about getting old services, when I always clear them, is weird (I do include a timestamp in the service record data, and I could always discard all but the last, but doesn't seem to be logical).
Any ideas? ANY help would be VERY appreciated, because writing the application is not funny any more (:-)=
Thanks a lot!
You need to wait until the clearLocalService call succeeds before adding the local service later. So put the addLocalService call into the onSuccess callback of the clearLocalServices.

Categories

Resources