watch face service data layer api - android

I got a problem with the Google android wear Data Layer Api...
I already used it to call handheld activities from a wearable activity and it worked just fine. But now I want call a handheld activity from a watchface service...
I created a Google API Client and added wearableApi:
public void onCreate(SurfaceHolder holder) {
super.onCreate(holder);
setWatchFaceStyle(new WatchFaceStyle.Builder(MyWatchFace.this)
.setCardPeekMode(WatchFaceStyle.PEEK_MODE_VARIABLE)
.setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
.setShowSystemUiTime(false)
.setAcceptsTapEvents(true)
.build());
mGoogleApiClient = new GoogleApiClient.Builder(MyWatchFace.this)
.addApi(Wearable.API)
.build();
mGoogleApiClient.connect();
Then I used these methods to send the data:
public void startActivity()
{
HashSet<String> results = new HashSet<String>();
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).setResultCallback(new ResultCallback<NodeApi.GetConnectedNodesResult>() {
#Override
public void onResult(NodeApi.GetConnectedNodesResult getConnectedNodesResult) {
String handheld = getConnectedNodesResult.getNodes().get(0).getId();
Toast.makeText(MyWatchFace.this, getConnectedNodesResult.getNodes().get(0).getDisplayName()+": "+ handheld, Toast.LENGTH_SHORT).show();
sendStartActivityMessage(handheld, giveValueXYZ());
}
});
private void sendStartActivityMessage(String nodeId, String data) {
byte[] dataArray = data.getBytes();
Toast.makeText(MyWatchFace.this, "ActivityPath: "+ START_ACTIVITY_PATH, Toast.LENGTH_SHORT).show();
Wearable.MessageApi.sendMessage(
mGoogleApiClient, nodeId, START_ACTIVITY_PATH, dataArray).setResultCallback(
new ResultCallback<MessageApi.SendMessageResult>() {
#Override
public void onResult(MessageApi.SendMessageResult sendMessageResult) {
if (!sendMessageResult.getStatus().isSuccess()) {
Log.e(TAG, "Failed to send message with status code: "
+ sendMessageResult.getStatus().getStatusCode());
}
}
});
}
On the mobile site I used this code to listen for the messages:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_host_main);
context = getApplicationContext();
...
//Google Api
final GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
.addApi(Wearable.API).build();
googleApiClient.connect();
Wearable.MessageApi.addListener(googleApiClient, this);
...
public void onMessageReceived(MessageEvent messageEvent) {
if (messageEvent.getPath().equals(START_ACTIVITY_PATH_WEARDATA)) {
Log.d(TAG, "getPath: " + messageEvent.getPath() + "|||getData: " + messageEvent.getData());
someActions();
}
All this works perfectly fine if I send the message from a wearable activity but does not even trigger the onMessageReceived(...) methode if I send a message from the watchface service...
Could there be a problem with my package names?
mobile :com.example.janik.xxx.xxx
watchface: de.WatchSmart.watch_smart_watch_face_service
How does the client know which Data Layer Api message is adressed to him?

Related

Google nearby - subscribe fails after publish

I am writing a sharing app using Google Nearby. I am using MESSAGES_API to publish a message and subscribe to others. The problem is that once a device publishes a message, it will no longer receive messages. I have several devices I am testing - any of which can initially publish a message and other devices receive it. However, if any of the other devices decide they want to publish, the original publisher fails to receive.
How can I continue to receive messages once I publish?
I init my google client here:
mGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.addApi(Nearby.MESSAGES_API)
.enableAutoManage(this, this)
.build();
after the google client is connected, I "subscribe' to it
Nearby.Messages.registerStatusCallback(mGoogleApiClient, new StatusCallback() {
#Override
public void onPermissionChanged(boolean b) {
super.onPermissionChanged(b);
Log.d(TAG, "Permission = " + b);
}
});
And, I have a listener to react to messages
Nearby.Messages.subscribe(mGoogleApiClient, mMessageListener).setResultCallback(new ErrorCheckingCallback("subscribe"));
MessageListener mMessageListener = new MessageListener() {
#Override
public void onFound(Message message) {
String messageAsString = new String(message.getContent());
Toast.makeText(mContext, "Incoming Image...", Toast.LENGTH_SHORT).show();
Log.d(TAG, "Found message: " + messageAsString);
}
#Override
public void onLost(Message message) {
String messageAsString = new String(message.getContent());
Log.d(TAG, "Lost sight of message: " + messageAsString);
}
};

How to obtain Google Fit data from Smart watch Wearable device Fossil Q Founder? Which complies BLE requirements? In Android

I am trying to pull the data from Intel's Fossil Android based Smartwatch (BLE device) via Google Fit Android SDK. The BLE Scan seem to happen, pairing occurs but inside the result Callback it doesn't go to onDeviceFound (I can proceed from there if it reaches). It eventually times out within few seconds from the start of the scan.
Any help would be appreciated.
Thanks for the docs link. I did go through all of that thoroughly but it didn't help. This is my Class file and I can call startBleScan from my MainActivity, the BleScan seems to be working, but after that it doesn't proceed to go on to onDeviceFound method.
public class BlueToothDevicesManager {
private static final String TAG = "BlueToothDevicesManager";
private static final int REQUEST_BLUETOOTH = 1001;
private Main2Activity mMonitor;
private GoogleApiClient mClient;
public BlueToothDevicesManager(Main2Activity monitor, GoogleApiClient client) {
mMonitor = monitor;
mClient = client;
}
public void startBleScan() {
if (mClient.isConnected()) {
Log.i(TAG, "Google account is connected");
}
BleScanCallback callback = new BleScanCallback() {
#Override
public void onDeviceFound(BleDevice device) {
Log.i(TAG, "BLE Device Found: " + device.getName());
claimDevice(device);
}
#Override
public void onScanStopped() {
Log.i(TAG, "BLE scan stopped");
}
};
PendingResult result = Fitness.BleApi.startBleScan(mClient, new StartBleScanRequest.Builder()
.setDataTypes(DataType.TYPE_POWER_SAMPLE, DataType.TYPE_STEP_COUNT_CADENCE, DataType.TYPE_STEP_COUNT_DELTA, DataType.TYPE_SPEED, DataType.TYPE_ACTIVITY_SAMPLE, DataType.TYPE_DISTANCE_DELTA, DataType.TYPE_ACTIVITY_SEGMENT, DataType.TYPE_LOCATION_SAMPLE)
.setBleScanCallback(callback)
.build());
result.setResultCallback(new ResultCallback() {
#Override
public void onResult(#NonNull Result result) {
Status status = result.getStatus();
if (!status.isSuccess()) {
String a = status.getStatusCode() + "";
Log.i(TAG, a);
switch (status.getStatusCode()) {
case FitnessStatusCodes.DISABLED_BLUETOOTH:
try {
status.startResolutionForResult(mMonitor, REQUEST_BLUETOOTH);
} catch (SendIntentException e) {
Log.i(TAG, "SendIntentException: " + e.getMessage());
}
break;
}
Log.i(TAG, "BLE scan unsuccessful");
} else {
Log.i(TAG, "ble scan status message: " + status.getStatusMessage());
Log.i(TAG, "Ble scan successful: " + status.getResolution());
}
}
});
}
public void claimDevice(BleDevice device) {
//Stop ble scan
//Claim device
PendingResult<Status> pendingResult = Fitness.BleApi.claimBleDevice(mClient, device);
pendingResult.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status st) {
if (st.isSuccess()) {
Log.i(TAG, "Claimed device successfully");
} else {
Log.e(TAG, "Did not successfully claim device");
}
}
});
}
}

Not able to send data from mobile app to wear app when both the apps implements the WearableListenerService

I have created a mobile app with an Activity which sends the data to wear. Mobile App Side the code is as below
Please note I have deleted some code to reduce the number of lines.
public class MainActivity extends AppCompatActivity implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
GoogleApiClient mGoogleClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Build a new GoogleApiClient for the the Wearable API
mGoogleClient = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
Button sendBtn = (Button) findViewById(R.id.send_btn);
sendBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mGoogleClient.isConnected()) {
Log.w("mobile-p", "connected.....sending data");
sendData();
}
}
});
}
// Connect to the data layer when the Activity starts
#Override
protected void onStart() {
super.onStart();
mGoogleClient.connect();
}
private void constructDataI temsForNotification() {
//I construct the dataItems here which needs to be passed to the wear
//and call the sendata.
sendData();
}
private void sendData() {
//Requires a new thread to avoid blocking the UI
if (mDataMapList != null && mDataMapList.size() > 0 ) {
new SendToDataLayerThread().start();
} else {
Log.w("mobile", "Nothing to notify");
}
}
#Override
public void onConnected(Bundle connectionHint) {
}
// Disconnect from the data layer when the Activity stops
#Override
protected void onStop() {
if (null != mGoogleClient && mGoogleClient.isConnected()) {
mGoogleClient.disconnect();
}
super.onStop();
}
// Placeholders for required connection callbacks
#Override
public void onConnectionSuspended(int cause) {
if (mGoogleClient != null) {
mGoogleClient.reconnect();
}
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) { }
//Use thread or asynctask.
class SendToDataLayerThread extends Thread {
public void run() {
// Construct a DataRequest and send over the data layer
PutDataMapRequest putDMR = PutDataMapRequest.create("/weardatapath");
putDMR.getDataMap().putDataMapArrayList("/weardatapath", mDataMapList);
PutDataRequest request = putDMR.asPutDataRequest();
DataApi.DataItemResult result = Wearable.DataApi.putDataItem(mGoogleClient, request).await();
if (result.getStatus().isSuccess()) {
for (DataMap mapItem : mDataMapList) {
Log.v("mobile-p", "DataMap: " + mapItem + " sent successfully to data layer ");
}
} else {
// Log an error
Log.v("mobile-p", "ERROR: failed to send DataMap to data layer");
}
}
}
}
On the Wear app side I have created a PhoneListenerService as below
public class PhoneListenerService extends WearableListenerService {
#Override
public void onDataChanged(DataEventBuffer dataEvents) {
DataMap dataMap;
for (DataEvent event : dataEvents) {
Log.v("Wear-W", "DataMap received on watch: " + DataMapItem.fromDataItem(event.getDataItem()).getDataMap());
// Check the data type
if (event.getType() == DataEvent.TYPE_CHANGED) {
// Check the data path
String path = event.getDataItem().getUri().getPath();
if (path.equals("/weardatapath")) {
DataMapItem dataMapItem = DataMapItem.fromDataItem(event.getDataItem());
ArrayList<DataMap> dataItems = dataMapItem.getDataMap().getDataMapArrayList
("dataMapItems");
// Broadcast DataMap contents to wearable show in notification..
if (dataItems != null && dataItems.size() > 0) {
for (DataMap item : dataItems) {
........
}
}
}
}
}
}
}
The above code works fine. Whenever I send a data from the MainActivity from mobileApp I do recieve it on the Wear app in PhoneListenerService.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
From the received data I build notifications on the wear app and for each action taken on the notification I want to notify to the mobile App. To do this I created PhoneSyncService on the wear app which will notify the mobile App on the actions taken..
public class PhoneSyncService extends IntentService implements
GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks{
private static final String "wearsrvc-w" = "PhoneSyncService-W";
public static final String ACTION_REPLY = "com.test.mobilewearsample.action.REPLY";
GoogleApiClient mGoogleClient;
public PhoneSyncService() {
super("PhoneSyncService");
}
#Override
public void onCreate() {
super.onCreate();
mGoogleClient = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
#Override
public void onDestroy() {
if (null != mGoogleClient && mGoogleClient.isConnected()) {
mGoogleClient.disconnect();
}
super.onDestroy();
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
final String action = intent.getAction();
Log.w("wearsrvc-w", "ACTION : "+action);
if (ACTION_REPLY.equals(action)) {
final String uId = intent.getStringExtra("dataId");
notifyHandheldDevice(uId);
}
}
}
private void notifyHandheldDevice(String uId) {
Log.v("wearsrvc-w", "in notify to handheld device :"+uId);
if (mGoogleClient.isConnected()) {
DataMap dataMap = new DataMap();
dataMap.putInt("uId", Integer.valueOf(uId));
PutDataMapRequest putDMR = PutDataMapRequest.create("/mobiledatapath");
putDMR.getDataMap().putAll(dataMap);
PutDataRequest request = putDMR.asPutDataRequest();
DataApi.DataItemResult result = Wearable.DataApi.putDataItem(mGoogleClient, request).await();
if (result.getStatus().isSuccess()) {
Log.v("wearsrvc-w" , "Wear DataMap: " + dataMap + " sent successfully to data layer ");
} else {
// Log an error
Log.v("wearsrvc-w" , "ERROR: failed to send DataMap to data layer");
}
}
Log.v("wearsrvc-w", "done notify to handheld device :"+uId);
}
#Override
public void onConnected(Bundle bundle) {
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
}
To get the data sent from wear app to the mobile App I created a WearDataListenerService as well on the mobile app , below is the code.
public class WearDataListenerService extends WearableListenerService {
private static final String TAG = "WearDataLstrService-M";
#Override
public void onDataChanged(DataEventBuffer dataEvents) {
for (DataEvent event : dataEvents) {
Log.v(TAG, "DataMap received on mobile: " + DataMapItem.fromDataItem(event.getDataItem()).getDataMap());
// Check the data type
Log.v(TAG, "event type :"+event.getType());
if (event.getType() == DataEvent.TYPE_CHANGED) {
// Check the data path
String path = event.getDataItem().getUri().getPath();
if (path.equals("/mobiledatapath")) {
DataMap dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
int uId = dataMap.getInt("dataId");
Log.v(TAG, "action received for uId :"+uId);
}
}
}
}
}
When I did the above changes I started to see a strange issue. When I try to send the data from the mobile app to the wear app the data is received on the WearDataListenerService which is on the mobile app side only and is not being received at the wear app side.
Its like the data sent from mobile app is received on the mobile app WearableListenerService instead of the one on wear app.
Can someone please help me.
Your mobile listener service has the following line:
if (path.equals("/mobiledatapath")) {}
I think you are closing the block too early; did you mean to do:
if (path.equals("/mobiledatapath")) {
// rest of that code
}
Your mobile side is adding/changing data so ANY node can receive a callback, including the mobile device, so that is why your mobile device receives it (and because of your faulty if-clause, it is not filtered out). As for the other part, what is the payload that you are sending in the data (mDataMapList)? Is that the same thing across multiple tries or it changes each time? There are two possible causes:
Your payload is the same so there is no "change", hence onDataChanged is not called for a second time (adding a, say, timestamp to data can address that)
in Play Services 8.3+, some changes were made to batch the data sync across network and transfer them not immediately (can be delayed up to 20 minutes); if an app needs immediate sync, they need to set the urgent flag, see setUrgent(). On the mobile side, teh change can be seen immediately (it is not crossing wire) but on the wear side, it can take a while unless send as urgent.

NullPointerException when creating GoogleApiClient instance

I've started creating Watch Face for Android Wear. I've implemented almost everything and now I want to show on the face the phone battery. From what I understood after my research this is only doable via Message or Data Layer API. So I've started working in his area but I'm facing a problem in the very beginning. I cannot connect to Google Api Client.
I have two classes under "wear" - one generic for the watch (service) and one created by me:
public class BatteryActivity extends Activity {
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks( new ConnectionCallbacks() {
#Override
public void onConnected(Bundle connectionHint) {
Log.i( "", "onConnected: " + connectionHint);
// Now you can use the Data Layer API
}
#Override
public void onConnectionSuspended(int cause) {
Log.i( "", "onConnectionSuspended: " + cause);
}
})
.addOnConnectionFailedListener( new OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i( "", "onConnectionFailed: " + result);
}
})
// Request access only to the Wearable API
.addApi(Wearable.API)
.build();
}
Whan I simply instance it like this: BatteryActivity batteryActivity = new BatteryActivity();
I get this error:
java.lang.NullPointerException: Attempt to invoke virtual method
'android.os.Looper android.content.Context.getMainLooper()' on a null
object reference
I don't understand how mGoogleApiClient is null if I've instance it.
As a note - this is purely based on google documentation here - https://developer.android.com/training/wearables/data-layer/messages.html
I suppose you should build the GoogleApiClient on onCreate method. Your code would be like this:
public class BatteryActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks( new ConnectionCallbacks() {
#Override
public void onConnected(Bundle connectionHint) {
Log.i( "", "onConnected: " + connectionHint);
// Now you can use the Data Layer API
}
#Override
public void onConnectionSuspended(int cause) {
Log.i( "", "onConnectionSuspended: " + cause);
}
})
.addOnConnectionFailedListener( new OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i( "", "onConnectionFailed: " + result);
}
})
// Request access only to the Wearable API
.addApi(Wearable.API)
.build();
}
}
It also happens when not providing proper context. Pass context like this :
mGoogleApiClient = new GoogleApiClient.Builder(context) // Pass context here
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API).build();
Ideally this should be done via Async task: https://developer.android.com/google/auth/api-client.html#Communicating
private class WatchTask extends AsyncTask<String, Void, Void> {
protected void doInBackground(String text) {
Or for a quick fix, you may just be using this in the wrong spot:
In your onCreate use getActivity() or this to use a Context for this line:
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
I would also suggest checking out: http://developer.android.com/training/wearables/data-layer/index.html
If you really want to use an activity, then it would look something like:
public class MainActivity extends Activity implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, MessageApi.MessageListener {
private GoogleApiClient googleClient; // A google client for Wear interaction
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Build a new GoogleApiClient that includes the Wearable API
googleClient = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
#Override
public void onConnected(Bundle connectionHint) {
Wearable.MessageApi.addListener(googleClient, this);
}
#Override
public void onMessageReceived(MessageEvent messageEvent) {
//Same onMessageReceived as in WearableListenerService
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) { }
#Override
public void onConnectionSuspended(int i) { }
}

Android Wear disconnection notification

I have an Android Wear app which communicates accelerometer values to an Handheld app.
I want to be notified in the Handheld app when connection with the android wear app has just been lost (when the Android Wear app is closed, for instance).
How must I implement that ?
Thank you for your help
Devices connected in the wear-to-device network are called Nodes. You can use the Node API to determine when devices enter or leave the network (e.g. when a wear device becomes disconnected from a phone).
https://developers.google.com/android/reference/com/google/android/gms/wearable/NodeApi.NodeListener
You can also use the Node API to get a list of all connected devices (e.g all wear devices connected to a phone) at any given time
https://developers.google.com/android/reference/com/google/android/gms/wearable/NodeApi
You can easily do this by extends the WearableListenerService and override onConnectedNodes() method.
Wearable Side
public class DisconnectListenerService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks {
/* the capability that the phone app would provide */
private static final String CONNECTION_STATUS_CAPABILITY_NAME = "is_connection_lost";
private GoogleApiClient mGoogleApiClient;
#Override
public void onCreate() {
super.onCreate();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.addConnectionCallbacks(this)
.build();
}
#Override
public void onConnectedNodes(List<Node> connectedNodes) {
if (mGoogleApiClient.isConnected()) {
updateStatus();
} else if (!mGoogleApiClient.isConnecting()) {
mGoogleApiClient.connect();
}
}
private void updateStatus() {
Wearable.CapabilityApi.getCapability(
mGoogleApiClient, CONNECTION_STATUS_CAPABILITY_NAME,
CapabilityApi.FILTER_REACHABLE).setResultCallback(
new ResultCallback<CapabilityApi.GetCapabilityResult>() {
#Override
public void onResult(CapabilityApi.GetCapabilityResult result) {
if (result.getStatus().isSuccess()) {
updateConnectionCapability(result.getCapability());
} else {
Log.e(TAG, "Failed to get capabilities, " + "status: " + result.getStatus().getStatusMessage());
}
}
});
}
private void updateConnectionCapability(CapabilityInfo capabilityInfo) {
Set<Node> connectedNodes = capabilityInfo.getNodes();
if (connectedNodes.isEmpty()) {
// The connection is lost !
} else {
for (Node node : connectedNodes) {
if (node.isNearby()) {
// The connection is OK !
}
}
}
}
#Override
public void onConnected(Bundle bundle) {
updateStatus();
}
#Override
public void onConnectionSuspended(int cause) {
}
#Override
public void onDestroy() {
if (mGoogleApiClient.isConnected() || mGoogleApiClient.isConnecting()) {
mGoogleApiClient.disconnect();
}
super.onDestroy();
}
}
Phone Side
create a xml file in values/ directory named wear.xml
<resources>
<string-array name="android_wear_capabilities">
<item>is_connection_lost</item>
</string-array>
</resources>

Categories

Resources