Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Send message from wearable to phone and then immediately reply

I've been battling with the Android Wear Message API all day today and have finally accepted I need some help with this.

My app is very straightforward. The Mobile portion consists of a MainActivity (which does nothing but display "Hello world" and a Service which extends WearableListenerService. The Wear portion is just a MainActivity with a single Button, and implements MessageApi.MessageListener.

The idea is simple: press the Button on the Wear device which sends a message to the Mobile. When the Mobile receives the message, it displays a Toast with the sender's message path (e.g. /mobile). Immediately after doing this, the Mobile should send a message back to the Wear device using my reply() method. All I want to do then is Log this message.

I can achieve the first part perfectly fine. When the Button is pressed, the Mobile pops up a Toast saying "/mobile". The reply, however, seems to just get lost in the aether; no errors, but no message either.

Can someone please help me understand what I'm doing wrong? I have pasted my files below.

This is the tutorial I am following. Cheers!

Wear: MainActivity.java

package org.thecosmicfrog.toastdroidmessageapitutorial;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.wearable.view.WatchViewStub;
import android.util.Log;
import android.view.View;

import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.wearable.MessageApi;
import com.google.android.gms.wearable.MessageEvent;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.Wearable;

import java.util.List;
import java.util.concurrent.TimeUnit;

public class MainActivity extends Activity implements MessageApi.MessageListener {

    private final String LOG_TAG = MainActivity.class.getSimpleName();

    private static final long CONNECTION_TIME_OUT_MS = 100;
    private static final String MOBILE_PATH = "/mobile";

    private GoogleApiClient googleApiClient;
    private String nodeId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initGoogleApiClient();

        final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
        stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
            @Override
            public void onLayoutInflated(WatchViewStub stub) {
                initWidgets();
            }
        });
    }

    private void initGoogleApiClient() {
        googleApiClient = getGoogleApiClient(this);
        retrieveDeviceNode();
    }

    private GoogleApiClient getGoogleApiClient(Context context) {
        return new GoogleApiClient.Builder(context)
                .addApi(Wearable.API)
                .build();
    }

    private void retrieveDeviceNode() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                if (googleApiClient != null && !(googleApiClient.isConnected() || googleApiClient.isConnecting()))
                    googleApiClient.blockingConnect(CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS);

                NodeApi.GetConnectedNodesResult result =
                        Wearable.NodeApi.getConnectedNodes(googleApiClient).await();

                List<Node> nodes = result.getNodes();

                if (nodes.size() > 0)
                    nodeId = nodes.get(0).getId();

                Log.v(LOG_TAG, "Node ID of phone: " + nodeId);

                googleApiClient.disconnect();
            }
        }).start();
    }

    private void initWidgets() {
        findViewById(R.id.button_toast).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendToast();
            }
        });
    }

    private void sendToast() {
        if (nodeId != null) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    if (googleApiClient != null && !(googleApiClient.isConnected() || googleApiClient.isConnecting()))
                        googleApiClient.blockingConnect(CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS);

                    Wearable.MessageApi.sendMessage(googleApiClient, nodeId, MOBILE_PATH, null).await();
                    googleApiClient.disconnect();
                }
            }).start();
        }
    }

    @Override
    public void onMessageReceived(MessageEvent messageEvent) {
        Log.v(LOG_TAG, "In onMessageReceived()");

        if (messageEvent.getPath().equals("/wear")) {
            Log.v(LOG_TAG, "Success!");
        }
    }
}

Mobile: ListenerService.java

package org.thecosmicfrog.toastdroidmessageapitutorial;

import android.util.Log;
import android.widget.Toast;

import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.wearable.MessageEvent;
import com.google.android.gms.wearable.Wearable;
import com.google.android.gms.wearable.WearableListenerService;

import java.util.concurrent.TimeUnit;

public class ListenerService extends WearableListenerService {

    private final String LOG_TAG = ListenerService.class.getSimpleName();

    private static GoogleApiClient googleApiClient;

    private static final long CONNECTION_TIME_OUT_MS = 100;
    private static final String WEAR_PATH = "/wear";
    private String nodeId;

    @Override
    public void onMessageReceived(MessageEvent messageEvent) {
        if (messageEvent.getPath().equals("/mobile")) {
            nodeId = messageEvent.getSourceNodeId();
            Log.v(LOG_TAG, "Node ID of watch: " + nodeId);
            showToast(messageEvent.getPath());

            reply(WEAR_PATH);
        }
    }

    private void showToast(String message) {
        Toast.makeText(this, message, Toast.LENGTH_LONG).show();
    }

    private void reply(final String path) {
        googleApiClient = new GoogleApiClient.Builder(getApplicationContext())
                .addApi(Wearable.API)
                .build();

        Log.v(LOG_TAG, "In reply()");
        Log.v(LOG_TAG, "Path: " + path);

        if (googleApiClient != null && !(googleApiClient.isConnected() || googleApiClient.isConnecting()))
            googleApiClient.blockingConnect(CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS);

        Wearable.MessageApi.sendMessage(googleApiClient, nodeId, path, null).await();
        googleApiClient.disconnect();
    }
}

The Mobile MainActivity is pretty trivial so I've left it out for clarity.

like image 314
Aaron Hastings Avatar asked Jan 12 '15 22:01

Aaron Hastings


1 Answers

You never call MessageApi.addListener() in your Wear activity so your MessageListener is never registered to receive messages. You should also call MessageApi.removeListener() when your activity is being destroyed.

Note: both methods require a connected GoogleApiClient. It may make logic easier if you leave a GoogleApiClient open throughout the duration of your activity rather than try connecting/removeListener()/disconnect in your onDestroy().

like image 108
ianhanniballake Avatar answered Oct 24 '22 11:10

ianhanniballake