Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 47d303fc authored by David Friedman's avatar David Friedman
Browse files

Docs: Adds filter-related and other info to Wear "Handling Data Layer Events".

Bug: 25703656
Change-Id: I056e805705a994a88dcc25406a934b929a3ebae5
parent d6a6f96b
Loading
Loading
Loading
Loading
+200 −102
Original line number Diff line number Diff line
@@ -69,71 +69,99 @@ if(result.getStatus().isSuccess()) {


<h2 id="Listen">Listen for Data Layer Events</h2>
<p>Because the data layer synchronizes and sends data across the handheld and
wearable, you normally want to listen for important events, such as when data items
are created, messages are received, or when the wearable and handset are connected.
<p>
Because the data layer synchronizes and sends data across the handheld and
wearable, it is usually necessary to listen for important events. Examples of
such events include creation of data items and receipt of messages.
</p>
<p>
To listen for data layer events, you have two options:
</p>
<p>To listen for data layer events, you have two options:</p>

<ul>
  <li>Create a service that extends
  <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>.
  </li>
  <li>Create an activity that implements
  <a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.DataListener.html"><code>DataApi.DataListener</code></a>.
  </li>
   <li>Create a service that extends <a href
="https://developer.android.com/reference/com/google/android/gms/wearable/WearableListenerService.html">
{@code WearableListenerService}</a>.</li>
   <li>Create an activity that implements <a
href="https://developer.android.com/reference/com/google/android/gms/wearable/DataApi.DataListener.html">
{@code DataApi.DataListener}</a>.</li>
</ul>

<p>With both these options, you override the data event callback methods for the events you
are interested in handling.</p>

<h3 id="listener-service">With a WearableListenerService</h3>

<p>
You typically create instances of this service in both your wearable and handheld apps. If you
are not interested in data events in one of these apps, then you don't need to implement this
service in that particular app.</p>

<p>For example, you can have a handheld app that sets and gets data item objects and a wearable app
that listens for these updates to update it's UI. The wearable never updates any of the data items,
so the handheld app doesn't listen for any data events from the wearable app.</p>

<p>You can listen for the following events with
<a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>:</p>

With both these options, you override the data event callback methods for the
events you are interested in handling.
</p>
<h3>With a WearableListenerService</h3>
<p>
You typically create instances of this service in both your wearable and
handheld apps. If you are not interested in data events in one of these apps,
then you don't need to implement this service in that particular app.
</p>
<p>
For example, you can have a handheld app that sets and gets data item objects
and a wearable app that listens for these updates to update its UI. The
wearable never updates any of the data items, so the handheld app doesn't
listen for any data events from the wearable app.
</p>
<p>
Some of the events you can listen for using <a
href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html">
{@code WearableListenerService}</a> are as follows:
</p>
<ul>
  <li><a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)"><code>onDataChanged()</code></a>
- Called when data item objects are created, changed, or deleted. An event on one side of a connection
triggers this callback on both sides.</li>
  <li><a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onMessageReceived(com.google.android.gms.wearable.MessageEvent)"><code>onMessageReceived()</code></a>
-  A message sent from one side of a connection triggers this callback on the other side of the connection.</li>
  <li><a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onMessageReceived(com.google.android.gms.wearable.MessageEvent)"><code>onPeerConnected()</code></a>
  and <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onPeerDisconnected(com.google.android.gms.wearable.Node)"><code>onPeerDisconnected()</code></a> -
  Called when the connection with the handheld or wearable is connected or disconnected.
  Changes in connection state on one side of the connection trigger these callbacks on both sides
  of the connection.
  <li><a
href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)">
{@code onDataChanged()}</a>:
Whenever a data item object is created, deleted, or changed, the system triggers
this callback on all connected nodes.
</li>
</ul>
<li><a
href="http://developer.android.com/reference/com/google/android/gms/wearable/WearableListenerService.html#onMessageReceived(com.google.android.gms.wearable.MessageEvent)">
{@code onMessageReceived()}</a>:  A message sent from a node triggers
this callback on the target node.</li>
<li><a
href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html#onCapabilityChanged(com.google.android.gms.wearable.CapabilityInfo)">
{@code onCapabilityChanged()}</a>:
When a capability that an instance of your app advertises becomes available
on the network, that event triggers this callback. If you're looking for a
nearby node you can query the
<a
href="https://developers.google.com/android/reference/com/google/android/gms/wearable/Node.html#isNearby()">
{@code isNearby()}</a> method of the nodes provided in the callback.</li>

<p>To create a <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>:</p>
<p>
In addition to those on this list, you can listen for events from
<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/ChannelApi.ChannelListener">
{@code ChannelApi.ChannelListener}</a>, such as
<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/ChannelApi.ChannelListener.html#onChannelOpened(com.google.android.gms.wearable.Channel)">
{@code onChannelOpened()}</a>.
</p>
</ul>
<p>To create a <a
href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>, follow these steps:</p>

<ol>
  <li>Create a class that extends
  <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>.
  <a
href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>.
  </li>
  <li>Listen for the events that you're interested in, such as
  <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)"><code>onDataChanged()</code></a>.
  <a
href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)">
<code>onDataChanged()</code></a>.
  </li>
  <li>Declare an intent filter in your Android manifest to notify the system about your
  <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>.
  This allows the system to bind your service as needed.
  <li>Declare an intent filter in your Android manifest to notify the system
about your
  <a
href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>
WearableListenerService</code></a>.
  This declaration allows the system to bind your service as needed.
  </li>
</ol>

  <p>The following example shows how to implement a simple
  <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>:
  <a
href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>
WearableListenerService</code></a>:
  </p>

<pre>
public class DataLayerListenerService extends WearableListenerService {

@@ -146,7 +174,7 @@ public class DataLayerListenerService extends WearableListenerService {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "onDataChanged: " + dataEvents);
        }
        final List<DataEvent> events = FreezableUtils
        final List events = FreezableUtils
                .freezeIterable(dataEvents);

        GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
@@ -179,85 +207,139 @@ public class DataLayerListenerService extends WearableListenerService {
}
</pre>

<p>Here's the corresponding intent filter in the Android manifest file:</p>
<p>
The next section explains how to use an intent filter with this listener.
</p>

<h3>Using filters with WearableListenerService</h3>

<p>
An intent filter for the
<a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html">
{@code WearableListenerService}</a> example shown in the previous section might look like this:

<pre>
&lt;service android:name=".DataLayerListenerService"&gt;
  &lt;intent-filter&gt;
      &lt;action android:name="com.google.android.gms.wearable.BIND_LISTENER" /&gt;
  &lt;intent-filter>
      &lt;action android:name="com.google.android.gms.wearable.DATA_CHANGED" /&gt;
      &lt;data android:scheme="wear" android:host="*"
               android:path="/start-activity" /&gt;
  &lt;/intent-filter&gt;
&lt;/service&gt;
</pre>


<h4>Permissions within Data Layer Callbacks</h4>

<p>
To deliver callbacks to your application for data layer events, Google Play services
binds to your <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>,
and calls your callbacks via IPC. This has the consequence
that your callbacks inherit the permissions of the calling process.</p>

<p>If you try to perform a privileged operation within a callback, the security check fails because your callback is
running with the identity of the calling process, instead of the identity of your app's
process.</p>

<p>To fix this, call {@link android.os.Binder#clearCallingIdentity} </a>,
to reset identity after crossing the IPC boundary, and then restore identity with
{@link android.os.Binder#restoreCallingIdentity restoreCallingIdentity()} when
you've completed the privileged operation:
In this filter, the {@code DATA_CHANGED} action replaces the
previously recommended {@code BIND_LISTENER} action so that only specific
events wake or launch your application. This change improves system efficiency
and reduces battery consumption and other overhead associated with your
application. In this example, the watch listens for the
{@code /start-activity} data item, and the
phone listens for the {@code /data-item-received} message response.
</p>
<p>
Standard Android filter matching rules apply. You can specify multiple services
per manifest, multiple intent filters per service, multiple actions per filter,
and multiple data stanzas per filter. Filters can match on a wildcard host or on
a specific one. To match on a wildcard host, use {@code host="*"}. To match
on a specific host, specify {@code host=&lt;node_id&gt;}.
</p>

<pre>
long token = Binder.clearCallingIdentity();
try {
    performOperationRequiringPermissions();
} finally {
    Binder.restoreCallingIdentity(token);
}
</pre>
<p>
You can also match a literal path or path prefix. If you are matching by path
or path prefix, you must specify a wildcard or specific host.
If you do not do so, the system ignores the path you specified.
</p>
<p>
For more information on the filter types that Wear supports, see the
API reference documentation for <a
href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService">
{@code WearableListenerService}</a>.

<h3 id="Listen">With a Listener Activity</h3>

</p>
<p>
If your app only cares about data layer events when the user is interacting
with the app and does not need a long-running service to handle every data
change, you can listen for events in an activity by implementing one or more
of the following interfaces:
For more information on data filters and matching rules, see the API reference
documentation for the <a
href="{@docRoot}guide/topics/manifest/data-element.html">{@code data}</a>
manifest element.
</p>


<p>When matching intent filters, there are two important rules to remember:</p>
<ul>
  <li><a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.DataListener.html"><code>DataApi.DataListener</code></a></li>
  <li><a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.MessageListener.html"><code>MessageApi.MessageListener</code></a></li>
  <li><a href="{@docRoot}reference/com/google/android/gms/wearable/NodeApi.NodeListener.html"><code>NodeApi.NodeListener</code></a></li>
    <li>If a scheme is not specified for the intent filter, the system ignores
    all the other URI attributes.</li>
    <li>If no host is specified for the filter, the system ignores the
    port attribute and all the path attributes.</li>
</ul>

<h3>With a listener activity</h3>
<p>
If your app only cares about data-layer events when the user is interacting
with the app, it may not need a long-running service to handle every data
change. In such a case, you can listen for events in an activity by
implementing one or more of the following interfaces:
</p>
<ul>
  <li><a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.DataListener.html"><code>
  DataApi.DataListener</code></a></li>

  <li><a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.MessageListener.html">
  <code>MessageApi.MessageListener</code></a></li>

  <li><a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi.CapabilityListener.html">{@code CapabilityApi.CapabilityListener}</a></li>
</ul>

<p>To create an activity that listens for data events:</p>
<ol>
<li>Implement the desired interfaces.</li>
<li>In {@link android.app.Activity#onCreate}, create an instance of
<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html"><code>GoogleApiClient</code></a>
to work with the Data Layer API.
<li>In {@link android.app.Activity#onCreate onCreate()}, create an instance of
<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html"><code>GoogleApiClient</code>
</a>to work with the Data Layer API.</li>

<li>
In {@link android.app.Activity#onStart onStart()}, call <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()"><code>connect()</code></a> to connect the client to Google Play services.
In {@link android.app.Activity#onStart onStart()}, call <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()">
<code>connect()</code></a> to connect the client to Google Play services.
</li>

<li>When the connection to Google Play services is established, the system calls
<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)"><code>onConnected()</code></a>. This is where you call
<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.DataApi.DataListener)"><code>DataApi.addListener()</code></a>,
  <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>,
  or <a href="{@docRoot}reference/com/google/android/gms/wearable/NodeApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.NodeApi.NodeListener)"><code>NodeApi.addListener()</code></a>
  to notify Google Play services that your activity is interested in listening for data layer events.
</li>

<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.DataApi.DataListener)">
<code>DataApi.addListener()</code></a>,

<a href="{@docRoot}android/reference/com/google/android/gms/wearable/CapabilityApi.CapabilityListener">
<code>MessageApi.addListener()</code></a>, or

<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient,%20com.google.android.gms.wearable.CapabilityApi.CapabilityListener,%20android.net.Uri,%20int)">
{@code CapabilityApi.addListener()}</a> to notify Google Play services that your activity is
interested in listening for data layer events.</li>

<li>In {@link android.app.Activity#onStop onStop()}, unregister any listeners with
<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.DataApi.DataListener)"><code>DataApi.removeListener()</code></a>,
<a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.MessageApi.MessageListener)"><code>MessageApi.removeListener()</code></a>,
or <a href="{@docRoot}reference/com/google/android/gms/wearable/NodeApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.NodeApi.NodeListener)"><code>NodeApi.removeListener()</code></a>.
</li>
<li>Implement <a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.DataListener.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)"><code>onDataChanged()</code>,
  <a href="{@docRoot}reference/com/google/android/gms/wearable/NodeApi.NodeListener.html#onPeerConnected(com.google.android.gms.wearable.Node)"><code>onMessageReceived()</code></a>,
    <a href="{@docRoot}reference/com/google/android/gms/wearable/NodeApi.NodeListener.html#onPeerConnected(com.google.android.gms.wearable.Node)"><code>onPeerConnected()</code></a>, and
  <a href="{@docRoot}reference/com/google/android/gms/wearable/NodeApi.NodeListener.html#onPeerDisconnected(com.google.android.gms.wearable.Node)"><code>onPeerDisconnected()</code></a>, depending on the interfaces that you implemented.
</li>
<a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.MessageApi.MessageListener)"><code>MessageApi.removeListener()</code></a>, or
<a href="http://developer.android.com/reference/com/google/android/gms/wearable/MessageApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient,%20com.google.android.gms.wearable.MessageApi.MessageListener)">
{@code CapabilityApi.removeListener()}</a>.</li>


<p>An alternative to adding listeners in
<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)"><code>onConnected()</code></a>
and removing them in
{@link android.app.Activity#onStop onStop()} is to add a filtered listener in an activity’s {@link android.app.Activity#onResume onResume()} and
remove it in {@link android.app.Activity#onPause onPause()}, so as to only receive data that is relevant to the
current application state.</p>


<li>Implement
<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.DataListener.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)">
<code>onDataChanged()</code></a>,
  <a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/MessageApi.MessageListener.html#onMessageReceived(com.google.android.gms.wearable.MessageEvent)">
  <code>onMessageReceived()</code></a>,
  <a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html#onCapabilityChanged(com.google.android.gms.wearable.CapabilityInfo)">
{@code onCapabilityChanged()}</a>,
or methods from <a href="http://developer.android.com/reference/com/google/android/gms/wearable/ChannelApi.ChannelListener.html">
Channel API listener methods</a>, depending on the interfaces that you implemented.</li>
</ol>

<p>Here's an example that implements
@@ -318,3 +400,19 @@ public class MainActivity extends Activity implements
    }
}
</pre>
<h3>Using Filters with Listener Activities</h3>
<p>
Just as you can specify intent filters for manifest-based
<a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html">
<code>WearableListenerService</code></a> objects, you can also use intent filters when registering a
listener through the Wearable API. The same rules are applicable to both
API-based listeners manifest-based listeners.
</p>

<p>
A common pattern is to register a listener with a specific path or path prefix
in an activity’s{@link android.app.Activity#onResume onResume()} method, and to
remove the listener in the activity’s {@link android.app.Activity#onPause onPause()} method.
Implementing listeners in this fashion allows your application to more selectively receive events,
improving its design and efficiency.
</p>