1page.title=Showing Information in Watch Faces
2
3@jd:body
4
5<div id="tb-wrapper">
6<div id="tb">
7<h2>This lesson teaches you to</h2>
8<ol>
9  <li><a href="#Experience">Create a Compelling Experience</a></li>
10  <li><a href="#AddData">Add Data to Your Watch Face</a></li>
11</ol>
12<h2>Related Samples</h2>
13<ul>
14<li><a href="{@docRoot}samples/WatchFace/index.html">
15WatchFace</a></li>
16</ul>
17<h2>You should also read</h2>
18<ul>
19  <li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li>
20</ul>
21</div>
22</div>
23
24<p>In addition to telling time, Android Wear devices provide users with contextually relevant
25information in the form of cards, notifications, and other wearable apps. Creating a custom
26watch face not only gives you the opportunity to tell time in visually compelling ways, but
27also to show users relevant information whenever they glance at their device.</p>
28
29<p>Like any other wearable app, your watch face can communicate with apps running on the handheld
30device using the <a href="{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer
31API</a>. In some cases, you need to create an activity in the handheld app module of your project
32that retrieves data from the Internet or from the user's profile and then shares it with your
33watch face.</p>
34
35<img src="{@docRoot}training/wearables/watch-faces/images/Render_Saturn.png"
36     width="200" height="196" alt="" style="margin-top:12px;margin-left:-20px"/>
37<img src="{@docRoot}training/wearables/watch-faces/images/Render_Episode.png"
38     width="200" height="196" alt="" style="margin-top:12px;margin-left:-25px"/>
39<p class="img-caption">
40<strong>Figure 1.</strong> Examples of watch faces with integrated data.</p>
41
42
43<h2 id="Experience">Create a Compelling Experience</h2>
44
45<p>Before you design and implement a contextually-aware watch face, answer the following
46questions:</p>
47
48<ul>
49<li>What kind of data do you want to incorporate?</li>
50<li>Where can you obtain this data?</li>
51<li>How often does the data change significantly?</li>
52<li>How can you present the data such that users understand it at a glance?</li>
53</ul>
54
55<p>Android Wear devices are usually paired with a companion device that has a GPS sensor and
56cellular connectivity, so you have endless possibilities to integrate different kinds of data
57in your watch face, such as location, calendar events, social media trends, picture feeds, stock
58market quotes, news events, sports scores, and so on. However, not all kinds of data are
59appropriate for a watch face, so you should consider what kinds of data are most relevant to
60your users throughout the day. Your watch face should also gracefully handle the case where the
61wearable is not paired with a companion device or when an Internet connection is not available.</p>
62
63<p>The active watch face on an Android Wear device is an app that runs continuously, so you
64must retrieve data in a battery-efficient manner. For example, you can obtain the current
65weather every ten minutes and store the results locally, instead of requesting an update every
66minute. You can also refresh contextual data when the device switches from ambient to interactive
67mode, since the user is more likely to glance at the watch when this transition occurs.</p>
68
69<p>You should summarize contextual information on your watch face, since there is limited
70space available on the screen and users just glance at their watch for a second or two at a
71time. Sometimes the best way to convey contextual information is to react to it using graphics
72and colors. For example, a watch face could change its background image depending on the current
73weather.</p>
74
75
76
77<h2 id="AddData">Add Data to Your Watch Face</h2>
78
79<div style="float:right;margin-left:20px">
80<img src="{@docRoot}training/wearables/watch-faces/images/preview_calendar.png"
81     width="180" height="180" alt="" style="margin-left:10px;margin-top:10px"/>
82<p class="img-caption"><strong>Figure 2.</strong> The calendar watch face.</p>
83</div>
84
85<p>The
86<a href="{@docRoot}samples/WatchFace/index.html">WatchFace</a>
87sample demonstrates how to obtain calendar data from the user’s profile in the
88<code>CalendarWatchFaceService</code> class and shows how many
89meetings there are in the following twenty-four hours.</p>
90
91<p>To implement a watch face that incorporates contextual data, follow these steps:</p>
92
93<ol>
94<li>Provide a task that retrieves the data.</li>
95<li>Create a custom timer to invoke your task periodically, or notify your watch face service
96    when external data changes.</li>
97<li>Redraw your watch face with the updated data.</li>
98</ol>
99
100<p>The following sections describe these steps in detail.</p>
101
102<h3 id="Task">Provide a task to retrieve data</h3>
103
104<p>Create a class inside your
105<a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html"><code>CanvasWatchFaceService.Engine</code></a>
106implementation that extends {@link android.os.AsyncTask} and add the code to retrieve the data
107you’re interested in.</p>
108
109<p>The <code>CalendarWatchFaceService</code> class obtains the number of meetings in the next
110day as follows:</p>
111
112<pre>
113/* Asynchronous task to load the meetings from the content provider and
114 * report the number of meetings back using onMeetingsLoaded() */
115private class LoadMeetingsTask extends AsyncTask&lt;Void, Void, Integer> {
116    &#64;Override
117    protected Integer doInBackground(Void... voids) {
118        long begin = System.currentTimeMillis();
119        Uri.Builder builder =
120                WearableCalendarContract.Instances.CONTENT_URI.buildUpon();
121        ContentUris.appendId(builder, begin);
122        ContentUris.appendId(builder, begin + DateUtils.DAY_IN_MILLIS);
123        final Cursor cursor = getContentResolver() .query(builder.build(),
124                null, null, null, null);
125        int numMeetings = cursor.getCount();
126        if (Log.isLoggable(TAG, Log.VERBOSE)) {
127            Log.v(TAG, "Num meetings: " + numMeetings);
128        }
129        return numMeetings;
130    }
131
132    &#64;Override
133    protected void onPostExecute(Integer result) {
134        /* get the number of meetings and set the next timer tick */
135        onMeetingsLoaded(result);
136    }
137}
138</pre>
139
140<p>The
141<a href="{@docRoot}reference/android/support/wearable/provider/WearableCalendarContract.html"><code>WearableCalendarContract</code></a>
142class from the Wearable Support Library provides direct access to the user's calendar events from
143the companion device.</p>
144
145<p>When the task finishes retrieving data, your code invokes a callback method. The following
146sections describe how to implement the callback method in detail.</p>
147
148<p>For more information about obtaining data from the calendar, see the <a
149href="{@docRoot}guide/topics/providers/calendar-provider.html">Calendar Provider</a> API
150guide.</p>
151
152<h3 id="Timer">Create a custom timer</h3>
153
154<p>You can implement a custom timer that ticks periodically to update your data.
155The <code>CalendarWatchFaceService</code> class uses a {@link android.os.Handler} instance
156that sends and processes delayed messages using the thread's message queue:</p>
157
158<pre>
159private class Engine extends CanvasWatchFaceService.Engine {
160    ...
161    int mNumMeetings;
162    private AsyncTask&lt;Void, Void, Integer> mLoadMeetingsTask;
163
164    /* Handler to load the meetings once a minute in interactive mode. */
165    final Handler mLoadMeetingsHandler = new Handler() {
166        &#64;Override
167        public void handleMessage(Message message) {
168            switch (message.what) {
169                case MSG_LOAD_MEETINGS:
170                    cancelLoadMeetingTask();
171                    mLoadMeetingsTask = new LoadMeetingsTask();
172                    mLoadMeetingsTask.execute();
173                    break;
174            }
175        }
176    };
177    ...
178}
179</pre>
180
181<p>This method initializes the timer when the watch face becomes visible:</p>
182
183<pre>
184&#64;Override
185public void onVisibilityChanged(boolean visible) {
186    super.onVisibilityChanged(visible);
187    if (visible) {
188        mLoadMeetingsHandler.sendEmptyMessage(MSG_LOAD_MEETINGS);
189    } else {
190        mLoadMeetingsHandler.removeMessages(MSG_LOAD_MEETINGS);
191        cancelLoadMeetingTask();
192    }
193}
194</pre>
195
196<p>The next timer tick is set in the <code>onMeetingsLoaded()</code> method, as shown in the next
197section.</p>
198
199<h3 id="Redraw">Redraw your watch face with the updated data</h3>
200
201<p>When the task that retrieves your data finishes, call the
202<a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#invalidate()"><code>invalidate()</code></a>
203method so the system redraws your watch face. Store your data inside member variables of the
204<code>Engine</code> class so you can access it inside the
205<a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#onDraw(android.graphics.Canvas, android.graphics.Rect)"><code>onDraw()</code></a>
206method.</p>
207
208<p>The <code>CalendarWatchFaceService</code> class provides a callback method for the task to
209invoke when it finishes retrieving calendar data:</p>
210
211<pre>
212private void onMeetingsLoaded(Integer result) {
213    if (result != null) {
214        mNumMeetings = result;
215        invalidate();
216    }
217    if (isVisible()) {
218        mLoadMeetingsHandler.sendEmptyMessageDelayed(
219                MSG_LOAD_MEETINGS, LOAD_MEETINGS_DELAY_MS);
220    }
221}
222</pre>
223
224<p>The callback method stores the result in a member variable, invalidates the view, and
225schedules the next timer tick to run the task again.</p>
226