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