Android Wear DataMap onDataChanged() not called for data from other device only

196 views Asked by At

I'm making a library that uses Android Wear's DataMap Api to send information between a Wear device and a phone. I've got the DataMap Api working with another project, but despite using the same steps, it doesn't seem to work in this one. If I use putDataItem on the wear device, or the phone, onDataChanged is only called on the device that changed the data, not the other device.

I've looked everywhere else I could find. I've included a timestamp in my data to make sure the data changes, I've set the PutDataRequest as Urgent with setUrgent() to make sure it gets sent immediately, and I've made sure the onResult returns true when I send the data. The gms versions in the manifest match, and I've tried setting up the intent filter in the manifest too.

Here's the code I've been using:

Phone Part:

package a.package.name; //I've changed this here, to hide stuff..  it's the same as below, though.
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.Result;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.wearable.Asset;
import com.google.android.gms.wearable.DataApi;
import com.google.android.gms.wearable.DataEvent;
import com.google.android.gms.wearable.DataEventBuffer;
import com.google.android.gms.wearable.DataMap;
import com.google.android.gms.wearable.DataMapItem;
import com.google.android.gms.wearable.PutDataMapRequest;
import com.google.android.gms.wearable.PutDataRequest;
import com.google.android.gms.wearable.Wearable;

public class WatchCommsPhone implements DataApi.DataListener, GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener, ResultCallback {

public static final String DATA_PATH_WATCH = "/watch_comms1";
public static final String DATA_PATH_PHONE = "/watch_comms2";

private GoogleApiClient gac;
Context c;

WatchCommsCallback wcc;

Handler h = new Handler();

public WatchCommsPhone(Context currentContext, WatchCommsCallback callback){
    wcc = callback;
    c = currentContext;
    gac = new GoogleApiClient.Builder(c).addApi(Wearable.API).addConnectionCallbacks(this).addOnConnectionFailedListener(this).build();
    gac.connect();
}

public void sendString(String message,long timestamp, String tag){

    PutDataMapRequest pdmr = PutDataMapRequest.create(DATA_PATH_PHONE);
    DataMap dm = pdmr.getDataMap();
    Asset a = Asset.createFromBytes(message.getBytes());
    dm.putAsset("data",a);
    dm.putLong("timestamp", timestamp);
    dm.putString("tag",tag);
    PutDataRequest pdr = pdmr.asPutDataRequest();
    pdr.setUrgent();
    Wearable.DataApi.putDataItem(gac,pdr).setResultCallback(this);
}

@Override
public void onConnected(@Nullable Bundle bundle) {
    Log.d("WatchCommsPhone","Watch Comms Watch: Connected");
    Wearable.DataApi.addListener(gac,this);

}

@Override
public void onConnectionSuspended(int i) {
    Log.d("WatchCommsPhone","Watch Comms Watch: Connection Suspended");
}

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
    Log.e("WatchCommsPhone","Watch Comms Watch: Connection Failed");
}

@Override
public void onDataChanged(DataEventBuffer dataEventBuffer) {  //This gets called when you get data!
    Log.d("WatchCommsPhone", "On Data Changed!");
    for (DataEvent event: dataEventBuffer){

        if (event.getType() == DataEvent.TYPE_CHANGED){
            Log.d("WatchCommsPhone","Got data of path: " + event.getDataItem().getUri().getPath());
            if(event.getDataItem().getUri().getPath().equals(DATA_PATH_WATCH)){
                Log.d("WatchCommsPhone","Got data from watch.");
                DataMap dm = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
                String tag = dm.getString("tag");
                Long timestamp = dm.getLong("timestamp");
                String data = dm.getString("data");
                ProcessData pd = new ProcessData(tag,data,timestamp);
                h.post(pd);
            }
        }
        }
}

@Override
public void onResult(@NonNull Result result) {
    Log.d("WatchCommsPhone","onResultCalled: " + result.getStatus().isSuccess());

}

public interface WatchCommsCallback{
    void onWatchMessageReceived(String tag, String message, long timestamp);
}

public class ProcessData implements Runnable{
    String tag;
    String data;
    Long timestamp;

    public ProcessData(String receivedTag, String receivedData, Long receivedTimestamp){
        tag = receivedTag;
        data = receivedData;
        timestamp = receivedTimestamp;
    }
    @Override
    public void run(){
        wcc.onWatchMessageReceived(tag,data,timestamp);
    }
}


}

Then the Wear part:

 package a.package.name; //I've changed this here, to hide stuff..  it's the same as above, though.
 import android.content.Context;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.util.Log;
 import com.google.android.gms.common.ConnectionResult;
 import com.google.android.gms.common.api.GoogleApiClient;
 import com.google.android.gms.common.api.Result;
 import com.google.android.gms.common.api.ResultCallback;
 import com.google.android.gms.wearable.Asset;
 import com.google.android.gms.wearable.DataApi;
 import com.google.android.gms.wearable.DataEvent;
 import com.google.android.gms.wearable.DataEventBuffer;
 import com.google.android.gms.wearable.DataMap;
 import com.google.android.gms.wearable.DataMapItem;
 import com.google.android.gms.wearable.PutDataMapRequest;
 import com.google.android.gms.wearable.PutDataRequest;
 import com.google.android.gms.wearable.Wearable;
    public class WatchCommsWatch implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, DataApi.DataListener, ResultCallback {

    public static final String DATA_PATH_WATCH = "/watch_comms1";
    public static final String DATA_PATH_PHONE = "/watch_comms2";


    Context c;
    GoogleApiClient gac;
    WatchCommsCallback wcc;

    Handler h = new Handler();

    public WatchCommsWatch(Context currentContext,WatchCommsCallback callback){
        wcc = callback;
        c = currentContext;
        gac = new GoogleApiClient.Builder(c).addApi(Wearable.API).addConnectionCallbacks(this).addOnConnectionFailedListener(this).build();
        gac.connect();
    }

    public void sendString(String message,long timestamp, String tag){

        PutDataMapRequest pdmr = PutDataMapRequest.create(DATA_PATH_WATCH);
        pdmr.setUrgent();
        DataMap dm = pdmr.getDataMap();
        Asset a = Asset.createFromBytes(message.getBytes());
        dm.putAsset("data",a);
        dm.putLong("timestamp", timestamp);
        dm.putString("tag",tag);
        PutDataRequest pdr = pdmr.asPutDataRequest();
        pdr.setUrgent();
        Wearable.DataApi.putDataItem(gac,pdr).setResultCallback(this);

    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        Log.d("WatchCommsWatch","Watch Connected.");
        Wearable.DataApi.addListener(gac,this);

    }

    @Override
    public void onConnectionSuspended(int i) {
        Log.d("WatchCommsWatch","Watch Connection Suspended.");
    }

    @Override
    public void onDataChanged(DataEventBuffer dataEventBuffer) {
        Log.d("WatchCommsWatch","onDataChanged Called.");
        for (DataEvent event: dataEventBuffer){
            if (event.getType() == DataEvent.TYPE_CHANGED){
                if(event.getDataItem().getUri().getPath().equals(DATA_PATH_WATCH)){
                    Log.d("WatchCommsWatch","Got data from watch.");
                    DataMap dm = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
                    String tag = dm.getString("tag");
                    Long timestamp = dm.getLong("timestamp");
                    Asset dataAsset = dm.getAsset("data");
                    //String data = new String(dataAsset.getData());
                    String data = tag;
                    ProcessData pd = new ProcessData(tag,data,timestamp);
                    h.post(pd);
                }
            }
        }
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        Log.e("WatchCommsWatch","WatchCommsWatch: Connection Failed.");
    }

    @Override
    public void onResult(@NonNull Result result) {
        Log.d("WatchCommsWatch","onResultCalled: " + result.getStatus().isSuccess());

    }
    public interface WatchCommsCallback{
        void onWatchMessageReceived(String message, String tag, long timestamp);
    }

    public class ProcessData implements Runnable{
        String tag;
        String data;
        Long timestamp;

        public ProcessData(String receivedTag, String receivedData, Long receivedTimestamp){
            tag = receivedTag;
            data = receivedData;
            timestamp = receivedTimestamp;
        }
        @Override
        public void run(){
            wcc.onWatchMessageReceived(tag,data,timestamp);
        }
    }
}

Thanks!

1

There are 1 answers

0
Nick Maletsky On

Of course you are free to choose their own way, but for my taste i prefer RXWear from Patloev https://github.com/patloew/RxWear See this snippet from my E52 watchface
Receive complex obj data from wear:

rxWear.message().listen("/dataMap", MessageApi.FILTER_LITERAL)
            .compose(MessageEventGetDataMap.noFilter())
            .subscribe(dataMap -> {
                // String title = dataMap.getString("title",           getString(R.string.no_message));
                if  (dataMap.containsKey("alWearTimersCategories")) {
                    String json =   dataMap.getString("alWearTimersCategories");
                    alTimersCategories=  allData.convertStringToALTimerWorkspace(json);
                    allData.setAlTimersCategoriesFromWear(alTimersCategories);
                    if (indata != null) {
                         timerdataset.refreshInternalData(alTimersCategories.get(   iActiveWorkSpaceindex).alTimersCategoryInWorkspace);
                    }




                }
            });

Send some to clock:

    rxWear.message().sendDataMapToAllRemoteNodes("/dataMap")
            .putString("timers", "TimersCategories")
            .putString("alTimersCategories", convertALTimerWorkspace(alTimersCategories))
            .toObservable()
            .subscribe(requestId -> {   });

}