Luan Nguyen c1609dc0b2 docs: Update information on delivering message to clarify that
MessageAPI is not reliable.

bug: 20088602
Change-Id: I2244598e5a155bc6e477d367287b8683ebdf019f
2015-04-28 11:36:42 -07:00

285 lines
12 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

page.title=Sending and Receiving Messages
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#SendMessage">Send a Message</a></li>
<li><a href="#ReceiveMessage">Receive a Message</a></li>
</ol>
<h2>Try it out</h2>
<ul>
<li>
<a href="https://github.com/googlesamples/android-FindMyPhone/" class="external-link">FindMyPhone</a>
</li>
</ul>
</div>
</div>
<p>You send messages using the
<a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.html"><code>MessageApi</code></a>
and attach the following items to the message:</p>
<ul>
<li>An arbitrary payload (optional)</li>
<li>A path that uniquely identifies the message's action</li>
</ul>
<p>
Unlike with data items, there is no syncing between the handheld and wearable apps.
Messages are a one-way communication mechanism that's good for remote procedure calls (RPC),
such as sending a message to the wearable to start an activity.</p>
<p>Multiple wearable devices can be connected to a users handheld device. Each connected device in
the network is considered a <em>node</em>. With multiple connected devices, you must consider which
nodes receive the messages. For example, in a voice transcription app that receives voice data on
the wearable device, you should send the message to a node with the processing power and battery
capacity to handle the request, such as a handheld device.</p>
<p class="note"><strong>Note:</strong>
With versions of Google Play services prior to 7.3.0, only one wearable device could be connected to
a handheld device at a time. You may need to update your existing code to take the multiple
connected nodes feature into consideration. If you dont implement the changes, your messages may
not get delivered to intended devices.
</p>
<h2 id="SendMessage">Send a Message</h2>
<p>A wearable app can provide functionality for users such as voice
transcription. Users can speak into their wearable device's microphone, and have a transcription
saved to a note. Since a wearable device typically does not have the processing power and battery
capacity required to handle the voice transcription activity, the app should offload this work to a
more capable, connected device.</p>
<p>The following sections show you how to advertise device nodes that can process activity
requests, discover the nodes capable of fulfilling a requested need, and send messages to those
nodes.
</p>
<h3 id="AdvertiseCapabilities">Advertise capabilities</h3>
<p>To launch an activity on a handheld device from a wearable device, use the
<a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.html"><code>MessageApi</code></a>
class to send the request. Since multiple wearables can be connected to the handheld device, the
wearable app needs to determine that a connected node is capable of launching the activity. In your
handheld app, advertise that the node it runs on provides specific capabilities.</p>
<p>To advertise the capabilities of your handheld app:</p>
<ol>
<li>Create an XML configuration file in the <code>res/values/</code> directory of your project and
name it <code>wear.xml</code>.
</li>
<li>Add a resource named <code>android_wear_capabilities</code> to <code>wear.xml</code>.
</li>
<li>Define capabilities that the device provides.
</li>
</ol>
<p class="note"><strong>Note:</strong>
Capabilities are custom strings that you define and must be unique within your app.
</p>
<p>The following example shows how to add a capability named <code>voice_transcription</code> to
<code>wear.xml</code>:</p>
<pre>
&lt;resources>
&lt;string-array name="android_wear_capabilities">
&lt;item>voice_transcription&lt;/item>
&lt;/string-array>
&lt;/resources>
</pre>
<h3 id="RetrieveCapabilities">Retrieve the nodes with the required capabilities</h3>
<p>Initially, you can detect the capable nodes by calling the <a
href="{@docRoot}reference/com/google/android/gms/wearable/CapabilityApi.html#getCapability(com.google.android.gms.common.api.GoogleApiClient, java.lang.String, int)"><code>CapabilityApi.getCapability()</code></a>
method.
The following example shows how to manually retrieve the results of reachable nodes with the
<code>voice_transcription</code> capability:</p>
<pre>
private static final String
VOICE_TRANSCRIPTION_CAPABILITY_NAME = "voice_transcription";
private GoogleApiClient mGoogleApiClient;
...
private void setupVoiceTranscription() {
CapabilityApi.GetCapabilityResult result =
Wearable.CapabilityApi.getCapability(
mGoogleApiClient, VOICE_TRANSCRIPTION_CAPABILITY_NAME,
CapabilityApi.FILTER_REACHABLE).await();
updateTranscriptionCapability(result.getCapability());
}
</pre>
<p>To detect capable nodes as they connect to the wearable device, register a <a
href="{@docRoot}reference/com/google/android/gms/wearable/CapabilityApi.CapabilityListener.html"><code>CapabilityApi.CapabilityListener()</code></a>
instance to your <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html"><code>GoogleApiClient</code></a>.
The following example shows how to register the listener and retrieve the results of reachable nodes
with the <code>voice_transcription</code> capability:</p>
<pre>
private void setupVoiceTranscription() {
...
CapabilityApi.CapabilityListener capabilityListener =
new CapabilityApi.CapabilityListener() {
&#64;Override
public void onCapabilityChanged(CapabilityInfo capabilityInfo) {
updateTranscriptionCapability(capabilityInfo);
}
};
Wearable.CapabilityApi.addCapabilityListener(
mGoogleApiClient,
capabilityListener,
VOICE_TRANSCRIPTION_CAPABILITY_NAME);
}
</pre>
<p class="note"><strong>Note:</strong>
If you create a service that extends
<a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>
to detect capability changes, you may want to override the
<a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onConnectedNodes(java.util.List<com.google.android.gms.wearable.Node>)"><code>onConnectedNodes()</code></a>
method to listen to finer-grained connectivity details, such as when a wearable device switches
from Wi-Fi to a Bluetooth connection to the handset. For an example implementation, see the
<code>DisconnectListenerService</code> class in the
<a href="https://github.com/googlesamples/android-FindMyPhone/" class="external-link">FindMyPhone</a>
sample. For more information on how to listen for important events, see
<a href="{@docRoot}training/wearables/data-layer/events.html#Listen">Listen for Data Layer Events</a>.
</p>
<p>After detecting the capable nodes, determine where to send the message. You should pick a node
that is in close proximity to your wearable device to
minimize message routing through multiple nodes. A nearby node is defined as one that is directly
connected to the device. To determine if a node is nearby, call the <a
href="{@docRoot}reference/com/google/android/gms/wearable/Node.html#isNearby()"><code>Node.isNearby()</code></a>
method.</p>
<p>The following example shows how you might determine the best node to use:</p>
<pre>
private String transcriptionNodeId = null;
private void updateTranscriptionCapability(CapabilityInfo capabilityInfo) {
Set&lt;Node> connectedNodes = capabilityInfo.getNodes();
transcriptionNodeId = pickBestNodeId(connectedNodes);
}
private String pickBestNodeId(Set&lt;Node> nodes) {
String bestNodeId = null;
// Find a nearby node or pick one arbitrarily
for (Node node : nodes) {
if (node.isNearby()) {
return node.getId();
}
bestNodeId = node.getId();
}
return bestNodeId;
}
</pre>
<h3 id="DeliverMessage">Deliver the message</h3>
<p>Once youve identified the best node to use, send the message using the
<a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.html"><code>MessageApi</code></a>
class.</p>
<p>The following example shows how to send a message to the transcription-capable node from a
wearable device. Verify that the node is available before you attempt to send the message. This call
is synchronous and blocks processing until the system queues the message for delivery.
</p>
<p class="note"><strong>Note:</strong> A successful result code does not guarantee delivery of the
message. If your app requires data reliability, use
<a href="{@docRoot}reference/com/google/android/gms/wearable/DataItem.html"><code>DataItem</code></a>
objects or the
<a href="{@docRoot}reference/com/google/android/gms/wearable/ChannelApi.html"><code>ChannelApi</code></a>
class to send data between devices.
</p>
<pre>
public static final String VOICE_TRANSCRIPTION_MESSAGE_PATH = "/voice_transcription";
private void requestTranscription(byte[] voiceData) {
if (transcriptionNodeId != null) {
Wearable.MessageApi.sendMessage(googleApiClient, transcriptionNodeId,
VOICE_TRANSCRIPTION_MESSAGE_PATH, voiceData).setResultCallback(
new ResultCallback<SendMessageResult>() {
&#64;Override
public void onResult(SendMessageResult sendMessageResult) {
if (!sendMessageResult.getStatus().isSuccess()) {
// Failed to send message
}
}
}
);
} else {
// Unable to retrieve node with transcription capability
}
}
</pre>
<p class="note"><strong>Note:</strong> To learn more about asynchronous and synchronous calls
to Google Play services and when to use each, see
<a href="{@docRoot}google/auth/api-client.html#Communicating">Communicate with Google Play
Services</a>.
</p>
<p>You can also broadcast messages to all connected nodes. To retrieve all of the
connected nodes that you can send messages to, implement the following code:</p>
<pre>
private Collection&lt;String&gt; getNodes() {
HashSet &lt;String&gt;results = new HashSet&lt;String&gt;();
NodeApi.GetConnectedNodesResult nodes =
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await();
for (Node node : nodes.getNodes()) {
results.add(node.getId());
}
return results;
}
</pre>
<h2 id="ReceiveMessage">Receive a Message</h2>
<p>
To be notified of received messages, implement the
<a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.MessageListener.html">
<code>MessageListener</code></a> interface to provide a listener for message events. Then,
register the listener with the
<a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.MessageApi.MessageListener)">
<code>MessageApi.addListener()</code></a> method. This example shows how you might implement the
listener to check the <code>VOICE_TRANSCRIPTION_MESSAGE_PATH</code>. If this condition is
<code>true</code>, start an activity to process the voice
data.
</p>
<pre>
&#64;Override
public void onMessageReceived(MessageEvent messageEvent) {
if (messageEvent.getPath().equals(VOICE_TRANSCRIPTION_MESSAGE_PATH)) {
Intent startIntent = new Intent(this, MainActivity.class);
startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startIntent.putExtra("VOICE_DATA", messageEvent.getData());
startActivity(startIntent);
}
}
</pre>
<p>
This is just a snippet that requires more implementation details. Learn about
how to implement a full listener service or activity in
<a href="{@docRoot}training/wearables/data-layer/events.html#Listen">Listening for Data Layer
Events</a>.
</p>