I'm following the same steps described here (the Google Fit client connection part is working fine).
final DataType dataType=TYPE_STEP_COUNT_DELTA;
DataSourcesRequest requestData = new DataSourcesRequest.Builder()
.setDataTypes(dataType) // At least one datatype must be specified.
.build();
Fitness.SensorsApi.findDataSources(mClient, requestData)
.setResultCallback(new ResultCallback<DataSourcesResult>() {
#Override
public void onResult(DataSourcesResult dataSourcesResult) {
Log.i(TAG, "Result: " + dataSourcesResult.getDataSources().size() + " sources "
+ dataSourcesResult.getStatus().toString());
for (DataSource dataSource : dataSourcesResult.getDataSources()) {
Log.i(TAG, "Data source found: " + dataSource.toString());
Log.i(TAG, "Data Source type: " + dataSource.getDataType().getName());
}
}
});
When I ask for data sources I get only one result which is the smartphone. If I add a listener then I really get data so it's working.
However it is also connected to an Android Wear smartwatch Gear Live with Android Wear app on the phone. Google Fit is installed in both of them but I'd like to get data from the smartwatch.
In the official guide I read
The Sensors API provides access to raw sensor data streams from
sensors available on the Android device and from sensors available in
companion devices, such as wearables.
This code is running on the smartphone so I think it would be right to expect data sources from companion smartwatch too. But it's like invisible to my phone application. Am I doing something wrong?
EDIT:
public class MainActivity extends AppCompatActivity {
private final static String TAG = "main_mobile";
private static final int REQUEST_OAUTH = 1;
private final static String DATE_FORMAT = "yyyy.MM.dd HH:mm:ss";
private static final String AUTH_PENDING = "auth_state_pending";
private boolean authInProgress = false;
private GoogleApiClient mClient = null;
private final static DataType dataType = TYPE_STEP_COUNT_DELTA;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null) {
authInProgress = savedInstanceState.getBoolean(AUTH_PENDING);
}
mClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.SENSORS_API)
.addApi(Fitness.RECORDING_API)
.addApi(Fitness.HISTORY_API)
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
.addConnectionCallbacks(connectionCallbacks)
.addOnConnectionFailedListener(connectionFailCallbacks)
.build();
}
private void initFitness() {
DataSourcesRequest requestData = new DataSourcesRequest.Builder()
.setDataTypes(dataType)
.build();
Fitness.SensorsApi.findDataSources(mClient, requestData)
.setResultCallback(new ResultCallback<DataSourcesResult>() {
#Override
public void onResult(DataSourcesResult dataSourcesResult) {
Log.i(TAG, "Result: " + dataSourcesResult.getDataSources().size() + " sources " + dataSourcesResult.getStatus().toString());
for (DataSource dataSource : dataSourcesResult.getDataSources()) {
Log.i(TAG, "\nData source found: \n\t" + dataSource.toString() + "\n\tType: " + dataSource.getDataType().getName());
}
}
});
}
#Override
protected void onStart() {
super.onStart();
Log.i(TAG, "Connecting...");
mClient.connect();
}
#Override
protected void onStop() {
super.onStop();
if (mClient.isConnected()) {
mClient.disconnect();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(AUTH_PENDING, authInProgress);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_OAUTH) {
authInProgress = false;
if (resultCode == RESULT_OK) {
// Make sure the app is not already connected or attempting to connect
if (!mClient.isConnecting() && !mClient.isConnected()) {
mClient.connect();
}
}
}
}
GoogleApiClient.ConnectionCallbacks connectionCallbacks = new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected!!!");
// Now you can make calls to the Fitness APIs.
// Put application specific code here.
initFitness();
}
#Override
public void onConnectionSuspended(int i) {
// If your connection to the sensor gets lost at some point,
// you'll be able to determine the reason and react to it here.
if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Log.i(TAG, "Connection lost. Cause: Network Lost.");
} else if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
Log.i(TAG, "Connection lost. Reason: Service Disconnected");
}
}
};
GoogleApiClient.OnConnectionFailedListener connectionFailCallbacks = new GoogleApiClient.OnConnectionFailedListener() {
// Called whenever the API client fails to connect.
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "Connection failed. Cause: " + result.toString());
if (!result.hasResolution()) {
// Show the localized error dialog
GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), MainActivity.this, 0).show();
return;
}
// The failure has a resolution. Resolve it.
// Called typically when the app is not yet authorized, and an
// authorization dialog is displayed to the user.
if (!authInProgress) {
try {
Log.i(TAG, "Attempting to resolve failed connection");
authInProgress = true;
result.startResolutionForResult(MainActivity.this, REQUEST_OAUTH);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Exception while starting resolution activity", e);
}
}
}
};
}
I have not tried any of this.
It seems as though the Samsung Gear Live Sensors are not supported out of the box, but you might be able to make it work via software sensors:
Your Gear Live
As said in this SO answer,
The Samsung Gear Live watch does not advertise itself as a BLE heart
rate monitor and therefore does not make the heart rate data
available via the normal Bluetooth Low Energy API or the Google
Fit API which is built upon it.
Supported Sensors
As said in the official docs,
Google Fit includes support for sensors on the mobile device and
Bluetooth Low Energy sensors paired with the device. Google Fit lets
developers implement support for other sensors and expose them as
software sensors in Android apps. Sensors supported by Google Fit are
available to Android apps as data source objects.
Possible Solution
It seems possible to implement additional software sensors.
(Copied template for this is at the bottom of the post, because it is lengthy).
You would get the data on the wearable following get-heart-rate-from-sensor-samsung-gear-live.
Template (from https://developers.google.com/fit/android/new-sensors)
Add this to your manifest file:
<service android:name="com.example.MySensorService"
android:process=":sensor">
<intent-filter>
<action android:name="com.google.android.gms.fitness.service.FitnessSensorService"/>
<!-- include at least one mimeType filter for the supported data types -->
<data android:mimeType="vnd.google.fitness.data_type/com.google.heart_rate.bpm"/>
</intent-filter>
</service>
and flesh this Service out:
import com.google.android.gms.common.*;
import com.google.android.gms.common.api.*;
import com.google.android.gms.fitness.*;
import com.google.android.gms.fitness.data.*;
import com.google.android.gms.fitness.service.*;
...
public class MySensorService extends FitnessSensorService {
#Override
public void onCreate() {
super.onCreate();
// 1. Initialize your software sensor(s).
// 2. Create DataSource representations of your software sensor(s).
// 3. Initialize some data structure to keep track of a registration for each sensor.
}
#Override
protected List<DataSource> onFindDataSources(List<DataType> dataTypes) {
// 1. Find which of your software sensors provide the data types requested.
// 2. Return those as a list of DataSource objects.
}
#Override
protected boolean onRegister(FitnessSensorServiceRequest request) {
// 1. Determine which sensor to register with request.getDataSource().
// 2. If a registration for this sensor already exists, replace it with this one.
// 3. Keep (or update) a reference to the request object.
// 4. Configure your sensor according to the request parameters.
// 5. When the sensor has new data, deliver it to the platform by calling
// request.getDispatcher().publish(List<DataPoint> dataPoints)
}
#Override
protected boolean onUnregister(DataSource dataSource) {
// 1. Configure this sensor to stop delivering data to the platform
// 2. Discard the reference to the registration request object
}
}
Related
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
I am using the Google Snapshot API in Android.
I use this code to get the user's activity and store it to Firebase.
//Get user's current activity
private void myCurrentActivity(final String timestamp) {
if (checkPermission()) {
Awareness.SnapshotApi.getDetectedActivity(mGoogleApiClient)
.setResultCallback(new ResultCallback<DetectedActivityResult>() {
#Override
public void onResult(#NonNull DetectedActivityResult detectedActivityResult) {
if (detectedActivityResult.getStatus().isSuccess()) {
Log.d(TAG, "myCurrentActivity - SUCCESS");
ActivityRecognitionResult activityRecognitionResult = detectedActivityResult.getActivityRecognitionResult();
databaseReference.child(getUID(getApplicationContext(), "myCurrentActivity")).child(timestamp).child("activity").setValue(getActivityString(activityRecognitionResult.getMostProbableActivity().getType()));
Log.d(TAG, "Most Propable Activity : " + getActivityString(activityRecognitionResult.getMostProbableActivity().getType()));
} else {
Log.d(TAG, "myCurrentActivity - FAILURE");
databaseReference.child(getUID(getApplicationContext(), "myCurrentActivity")).child(timestamp).child("activity").setValue("null");
}
}
});
}
}
The problem is that the onResult function is never executed when i run it.
Do you have any ideas what may cause this ?
Thank you.
EDIT: I just ran it in the emulator and it's working without problems. Is it possible that this has something to do with my device ?
Ì am trying to connect with beacons in my android app. But I can't seem to find my beacons. I am using Ibeacons. I am using the AltBeacon Library. The onBeaconServiceConnect starts and the didDetermineStateForRegion follows. But didEnterReion never gets called. This is my code:
public class ListScenarios extends AppCompatActivity implements BeaconConsumer, MonitorNotifier {
private static final String TAG = "ListScenarios";
private ListView listView;
public String persoonID;
public String adresID;
public Array beaconArray;
//private ArrayList<IBeacon> arrBeacons = new ArrayList<>();
private BeaconManager mBeaconManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_scenarios);
// Setup beaconmanager
mBeaconManager = BeaconManager.getInstanceForApplication(this.getApplicationContext());
// Detect iBeacon
mBeaconManager.getBeaconParsers().add(new BeaconParser()
.setBeaconLayout("m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"));
mBeaconManager.bind(this);
//listview
listView = (ListView) findViewById(R.id.list_scenario);
//send request to load list
getScenarios();
getBeacons();
}
// MARK: - Bluetooth
#Override
public void onBeaconServiceConnect() {
System.out.println("We are in onBeaconServiceConnect");
// Set the two identifiers below to null to detect any beacon regardless of identifiers
Identifier myBeaconNamespaceId = null;
Identifier myBeaconInstanceId = null;
Region region = new Region("my-beacon-region", myBeaconNamespaceId, myBeaconInstanceId, null);
mBeaconManager.addMonitorNotifier(this);
try {
mBeaconManager.startMonitoringBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void didEnterRegion(Region region) {
System.out.println("We are in didEnterRegion");
Log.d(TAG, "I detected a beacon in the region with namespace id " + region.getId1() +
" and instance id: " + region.getId2());
}
public void didExitRegion(Region region) {
System.out.println("We are in didExitRegion");
}
public void didDetermineStateForRegion(int state, Region region) {
System.out.println("We are in didDetermineStateForRegion");
}
#Override
public void onPause() {
super.onPause();
mBeaconManager.unbind(this);
}
Two things to check:
Make sure you are using the correct BeaconParser expression. The expression shown in the question is for AltBeacon: "m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25. If you are trying to detect iBeacon, you'll need to use a different expression. This site has a handy reference: https://beaconlayout.wordpress.com/
If you are running your app on Android 6+ and are targeting SDK 23 or higher, you need to dynamically request location permission for your app. If you don't do this, you will get no detections, and you will see this in the logs: 04-22 22:35:20.152 5158 5254 E BluetoothUtils: Permission denial: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results You can read how to do this here: http://altbeacon.github.io/android-beacon-library/requesting_permission.html
I am working on the udacity wearable course and unable to get my wearable emulator to send dataEvents to the wearable device.
On both the handheld and the wearable I have services that extend the WearableListenerService (WLS). The handheld version is currently started via a startService call in the activity, the wearable service is started in the watchface service also with startService, both services can be seen as started.
The device WLS successfully makes a call to the content provider and attempts at sending the data to the wearable, but putDataItem resultCallback is never called.
The wearable seems to be paired with my phone as I receive various notifications on it from my phone, so the setup is good. Both the handheld and wearable modules have the service added to the manifest with the required intent-filter, and with logging I can see they are both starting up as expected.
I am following the docs, but I must be missing something.
Thanks for any help.
Handheld service
public class WeatherDataService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private static final String TAG = "HandheldService";
private GoogleApiClient mGoogleClientApi;
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "initializing");
mGoogleClientApi = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleClientApi.connect();
}
#Override
public void onPeerConnected(Node peer) {
super.onPeerConnected(peer);
Log.d(TAG, "onPeerConnected: " + peer.getDisplayName());
String[] temps = getCurrentTemps();
if (temps != null && temps.length == 2) {
Log.d(TAG, String.format("onPeerConnected: temps %s %s", temps[0], temps[1]));
notifyWearables(mGoogleClientApi, temps[0], temps[1]);
}
}
private void notifyWearables(GoogleApiClient client, String low, String high) {
Log.d(TAG, String.format("notifyWearables: %s %s", low, high));
PutDataMapRequest map = PutDataMapRequest.create("/weather");
map.getDataMap().putString("tempLow", low);
map.getDataMap().putString("tempHigh", high);
PutDataRequest request = map.asPutDataRequest();
Wearable.DataApi.putDataItem(client, request).setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
#Override
public void onResult(DataApi.DataItemResult result) {
Log.d(TAG, String.format("onResult, %s", result.getStatus().getStatusMessage()));
if (!result.getStatus().isSuccess()) {
Log.d(TAG, "onResult: Failed to send data");
}
}
});
...
}
Wearable service
public class WeatherDataService extends WearableListenerService {
private static final String TAG = "Wearable:Service";
#Override
public void onCreate() {
super.onCreate();
// this is called
Log.d(TAG, "onCreate");
}
#Override
public void onDataChanged(DataEventBuffer dataEvents) {
// NEVER makes it here
Log.d(TAG, "onDataChanged: ");
for (DataEvent dataEvent : dataEvents) {
Log.d(TAG, "onDataChanged: " + dataEvent.getDataItem().getUri().getPath());
if (dataEvent.getType() == DataEvent.TYPE_CHANGED) {
Log.d(TAG, "onDataChanged: TYPE_CHANGED");
DataMap dataMap = DataMapItem.fromDataItem(dataEvent.getDataItem()).getDataMap();
String path = dataEvent.getDataItem().getUri().getPath();
if (path.equals("/weather")) {
Log.d(TAG, "onDataChanged: /weather");
String tempLow = dataMap.getString("tempLow");
String tempHigh = dataMap.getString("tempHigh");
Log.d(TAG, "onDataChanged: " + tempLow + " " + tempHigh);
}
}
}
}
}
Update
I was missing the mGoogleApiClient.connect() method call. The putDataItem resultCallback is now being called, unforunately the wearable device's onDataChanged event is not being called.
onDataChanged
doesn't call because you doesn't change any data that sent to wear every time(it's call only when the data really did change), try to send different data and it will work, and make sure to connect your mGoogleClientApi
in onStrart();
It turned out there was a couple things wrong with things.
The first was what #mahmoud mentioned, although I missed it the first time I read it, in that mGoogleClientApi.connect() needed to be called. When #mahmoud said connect to the client in onStart() I didn't read that as call the .connect() method.
The second things that was wrong was that the manifest package attributes did not match for each the modules. I thought they needed the same parent namespaces.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.sunshine.app">
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.