Communication between Wearable and Smartphone

Category: 


In the last tutorial we've learned how to add a configuration activity for a watchface. Now we want to learn how to send settings from a mobile app to the watchface.

Handheld UI

For sake of simplicity we don't create a beautiful, complex UI, but a very simple one, with only two buttons. The first button will make the hour hand blue and the other one red.
First of all we change the text and the onClick Event of each button.

For each name we specify as the onClick handler (eg onClickRed), we must specify a corresponding method in the activity. This method is called whenever the user clicks on that button. In those methods we finally call the (not yet implemented) sendMessage method.

public void onClickRed(View view) {
        sendMessage("red");
}

public void onClickBlue(View view) {
        sendMessage("blue");
}

Send Message

As an entrypoint for the MessageApi, a GoogleApiClient is needed. The client is created by a Builder. We're only interested in the Wearable API, so we only need to add that API. We can add more APIs if necessary.

The path of a message must start with a slash!

private final static String PATH = "/CONFIG";
private final static String TAG = "SAMPLE_WATCH";
private final static int CONNECTION_TIME_OUT_MS = 100;
private String nodeId;
private void sendMessage(final String msg) {
  final GoogleApiClient client =
    new GoogleApiClient.Builder(this).addApi(Wearable.API).build();

  new Thread(new Runnable() {
    @Override
    public void run() {
      client.blockingConnect(CONNECTION_TIME_OUT_MS,
        TimeUnit.MILLISECONDS);
      if(nodeId==null) {
        NodeApi.GetConnectedNodesResult result =
          Wearable.NodeApi.getConnectedNodes(client).await();
        List<Node> nodes = result.getNodes();
        if (nodes.size() > 0) {
          nodeId = nodes.get(0).getId();
        } else {
          Log.d(TAG, "no nodes");
          client.disconnect();
          return;
        }
      }

      Wearable.MessageApi.sendMessage(client, nodeId,
        PATH, msg.getBytes());
      client.disconnect();
    }
  }).start();
}

It needs some time to query the ID and to send a message, so it would be better to run that code in another thread, so the UI will not block. We implement the thread, or more precisely the runnable, with an inner class. We need the ID of our wearable device, so we need to query it. This is done via the getConnectedNodes method. If there are no connected devices, we output a log message and disconnect. Otherwise we store the ID and send our message. Afterwards we disconnect again and we're finished with the mobile part.

Receive Messages

Now the watchface should receive messages. First of all we add some variables to our watchface:

private final static String PATH = "/CONFIG";
private final static String TAG = "SAMPLE_WATCH";
private GoogleApiClient mClient;

The wearable should always be able to receive a message, so we need to connect our GoogleApiClient at the beginning and only disconnect when our app is closed.

@Override
public void onCreate(SurfaceHolder holder) {
  ...
  mClient = new GoogleApiClient.Builder(SampleWatchfaceService.this)
    .addApi(Wearable.API).build();
  mClient.connect();
  ...
}
@Override
public void onDestroy() {
  ...
  mClient.disconnect();
}

Next we need to implement our receiver. This is done via a Listener. Each registered listener will be called by the system when a message is received. But we have to make sure that we only process our own messages. We then change the current color depending on the received text and redraw our watchface.

public void onCreate(SurfaceHolder holder) {
  ...
  Wearable.MessageApi.addListener(mClient,
    new MessageApi.MessageListener() {
      @Override
      public void onMessageReceived(MessageEvent messageEvent) {
        if(messageEvent.getPath().equals(PATH)) {
          String data = new String(messageEvent.getData());
          if(data.equals("red"))
            mHourPaint.setARGB(255, 255, 0, 0);
          else if(data.equals("blue"))
            mHourPaint.setARGB(255, 0, 0, 255);
          invalidate();
        }
      }
    }
  );
}

And that's all! We are now able to send and receive messages.

If you have any questions or remarks, please leave a comment.