Home | History | Annotate | Download | only in watch-faces
      1 page.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">
     15 WatchFace</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
     25 information in the form of cards, notifications, and other wearable apps. Creating a custom
     26 watch face not only gives you the opportunity to tell time in visually compelling ways, but
     27 also 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
     30 device using the <a href="{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer
     31 API</a>. In some cases, you need to create an activity in the handheld app module of your project
     32 that retrieves data from the Internet or from the user's profile and then shares it with your
     33 watch 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
     46 questions:</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
     56 cellular connectivity, so you have endless possibilities to integrate different kinds of data
     57 in your watch face, such as location, calendar events, social media trends, picture feeds, stock
     58 market quotes, news events, sports scores, and so on. However, not all kinds of data are
     59 appropriate for a watch face, so you should consider what kinds of data are most relevant to
     60 your users throughout the day. Your watch face should also gracefully handle the case where the
     61 wearable 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
     64 must retrieve data in a battery-efficient manner. For example, you can obtain the current
     65 weather every ten minutes and store the results locally, instead of requesting an update every
     66 minute. You can also refresh contextual data when the device switches from ambient to interactive
     67 mode, 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
     70 space available on the screen and users just glance at their watch for a second or two at a
     71 time. Sometimes the best way to convey contextual information is to react to it using graphics
     72 and colors. For example, a watch face could change its background image depending on the current
     73 weather.</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>
     87 sample demonstrates how to obtain calendar data from the users profile in the
     88 <code>CalendarWatchFaceService</code> class and shows how many
     89 meetings 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>
    106 implementation that extends {@link android.os.AsyncTask} and add the code to retrieve the data
    107 youre interested in.</p>
    108 
    109 <p>The <code>CalendarWatchFaceService</code> class obtains the number of meetings in the next
    110 day 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() */
    115 private 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>
    142 class from the Wearable Support Library provides direct access to the user's calendar events from
    143 the companion device.</p>
    144 
    145 <p>When the task finishes retrieving data, your code invokes a callback method. The following
    146 sections 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
    149 href="{@docRoot}guide/topics/providers/calendar-provider.html">Calendar Provider</a> API
    150 guide.</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.
    155 The <code>CalendarWatchFaceService</code> class uses a {@link android.os.Handler} instance
    156 that sends and processes delayed messages using the thread's message queue:</p>
    157 
    158 <pre>
    159 private 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
    185 public 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
    197 section.</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>
    203 method 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>
    206 method.</p>
    207 
    208 <p>The <code>CalendarWatchFaceService</code> class provides a callback method for the task to
    209 invoke when it finishes retrieving calendar data:</p>
    210 
    211 <pre>
    212 private 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
    225 schedules the next timer tick to run the task again.</p>
    226