1

I have set up a connection between my wear and mobile devices by following this post. I am sending an asset from the wearable to he handheld. However, the onDataChanged method is not being called, even though the devices are connected and the dataitem is being successfully sent. I have tried most other solutions, including making sure my build.gradles have the same appId, the same wearable version numbers. I have added a timestamp to the datamap, and yet it is still not working. Has anyone else ran into this problem or have any other ideas as to why it might not be getting called? Thanks.

Here's my wearable code which is doing the sending:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main_wear);
    mContainerView = (BoxInsetLayout) findViewById(R.id.container);

    //...

    // Build a new GoogleApiClient for the Wearable
    googleClient = new GoogleApiClient.Builder(this)
            .addApi(Wearable.API)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();
}

@Override
protected void onStart() {
    super.onStart();
    if(!googleClient.isConnected()) {
        googleClient.connect();
    }
}

public void sendToPhone(View view){
    // Send audio
    if(audioAsset != null){
        new SendToDataLayer().start();
    }
}

private class SendToDataLayer extends Thread{

    public void run(){
        // Sending audio
        // Get connected wearable nodes
        NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleClient).await();
        for(Node node : nodes.getNodes()){
            // Send the audio
            PutDataMapRequest request = PutDataMapRequest.create("/audio");
            DataMap map = request.getDataMap();
            map.putLong("time", new Date().getTime());
            map.putAsset("audioAsset", audioAsset);
            Wearable.DataApi.putDataItem(googleClient, request.asPutDataRequest());
            Log.d("PUTDAT", "Data put on data item, for node: " + node.getDisplayName());
        }
    }
}

Using the log.d call I can see that the device is connected and that the data is being sent, or at least appears to be.

My code for the handheld receiving end:

public class MainHandheldActivity extends AppCompatActivity implements DataApi.DataListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{

    GoogleApiClient googleClient;
    MessageReceiver messageReceiver;
    IntentFilter messageFilter;

    byte[] audioBytes;
    private final Handler handler = new Handler();
    private String nodeId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_handheld);
        audioBytes = null;

        // Build a new GoogleApiClient
        googleClient = new GoogleApiClient.Builder(this)
                .addApi(Wearable.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();

        retrieveDeviceNodes();

        // Register the local broadcast receiver
        messageFilter = new IntentFilter(Intent.ACTION_SEND);
        messageReceiver = new MessageReceiver();
        LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, messageFilter);
    }

    private void retrieveDeviceNodes(){

        new Thread(new Runnable() {
            @Override
            public void run() {
                googleClient.blockingConnect(3000, TimeUnit.MILLISECONDS);
                NodeApi.GetConnectedNodesResult result =
                        Wearable.NodeApi.getConnectedNodes(googleClient).await();
                List<Node> nodes = result.getNodes();
                if (nodes.size() > 0) {
                    nodeId = nodes.get(0).getId();
                }
                googleClient.disconnect();
            }
        }).start();
    }

    @Override
    public void onDataChanged(DataEventBuffer dataEventBuffer) {

        Toast.makeText(this, "Data Changed!", Toast.LENGTH_LONG).show();

        for (DataEvent event : dataEventBuffer) {
            Log.d(TAG, "Data received: " + event.getDataItem().getUri());

            if (event.getType() == DataEvent.TYPE_CHANGED &&
                    event.getDataItem().getUri().getPath().equals("/audio")) {
                DataMapItem dataMapItem = DataMapItem.fromDataItem(event.getDataItem());
                Asset audioAsset = dataMapItem.getDataMap().getAsset("audioAsset");
                audioBytes = loadBytesFromAsset(audioAsset);
            }

            // Enable player
            handler.post(onNewAudio());
        }
    }

    public byte[] loadBytesFromAsset(Asset asset) {
        if (asset == null) {
            throw new IllegalArgumentException("Asset must be non-null");
        }

        ConnectionResult result = googleClient.blockingConnect(3000, TimeUnit.MILLISECONDS);
        if(!result.isSuccess()){
            return null;
        }

        // Convert asset into a file descriptor and block until it's ready
        InputStream assetInputStream = Wearable.DataApi.getFdForAsset(googleClient, asset).await().getInputStream();

        if (assetInputStream == null) {
            Log.w(TAG, "Requested an unknown Asset.");
            return null;
        }
        // Decode the stream into a byte[]
        return getBytesFromInputStream(assetInputStream);
    }

    private Runnable onNewAudio() {
        return new Runnable() {
            @Override
            public void run() {
                // Enable player
            }
        };
    }

    @Override
    public void onConnected(Bundle bundle) {
        Wearable.DataApi.addListener(googleClient, this);
        Toast.makeText(this, "AddedListener!", Toast.LENGTH_LONG).show();
    }

    @Override
    protected void onStart() {
        super.onStart();
        if(!googleClient.isConnected()) {
            googleClient.connect();
        }
        LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, messageFilter);
    }
}

The Toast in onDataChanged() never gets shown, nor does the log call. Also, here is my handheld manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest
    package="glasgow.comsTest"
    xmlns:android="http://schemas.android.com/apk/res/android">


    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version"/>

        <service
            android:name=".ListenerService">
            <intent-filter>
                <action android:name="com.google.android.gms.wearable.BIND_LISTENER"/>
            </intent-filter>
        </service>

        <activity android:name=".MainHandheldActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>
Community
  • 1
  • 1
Highway62
  • 800
  • 1
  • 10
  • 25

1 Answers1

0

The loop that you have on the sender side is not needed; in fact if you look inside the loop, you are not using the "node" that you are looping through. Adding a data item will sync that over all the connected nodes. In addition, in the latest Play Services, the sync process of DataApi is not immediate; it is batched up and run periodically (it can take up to 20 minutes but often takes a few minutes) and that is done to save battery and other resources but if an app needs an immediate sync, then one has to set the appropriate urgent flag on the item (see setUrgent()). Please do the following:

  1. Remove the loop
  2. If needed, set the urgent flag.
Ali Naddaf
  • 16,951
  • 2
  • 21
  • 28
  • isUrgent doesn't seem to be able to be called on the PutDataRequest object, any ideas? See [here](http://i.imgur.com/ULvBfON.png) – Highway62 Dec 24 '15 at 02:19
  • Make sure you have the latest play services (v8.3) as a dependency in your build.gradle file. – Ali Naddaf Dec 24 '15 at 03:02