MessageAPI is not reliable. bug: 20088602 Change-Id: I2244598e5a155bc6e477d367287b8683ebdf019f
285 lines
12 KiB
Plaintext
285 lines
12 KiB
Plaintext
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 user’s 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 don’t 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>
|
||
<resources>
|
||
<string-array name="android_wear_capabilities">
|
||
<item>voice_transcription</item>
|
||
</string-array>
|
||
</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() {
|
||
@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<Node> connectedNodes = capabilityInfo.getNodes();
|
||
|
||
transcriptionNodeId = pickBestNodeId(connectedNodes);
|
||
}
|
||
|
||
private String pickBestNodeId(Set<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 you’ve 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>() {
|
||
@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<String> getNodes() {
|
||
HashSet <String>results = new HashSet<String>();
|
||
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>
|
||
@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> |