Home | History | Annotate | Download | only in watch-faces
      1 page.title=Drawing 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="#Initialize">Initialize Your Watch Face</a></li>
     10   <li><a href="#SystemUI">Configure the System UI</a></li>
     11   <li><a href="#Screen">Obtain Information About the Device Screen</a></li>
     12   <li><a href="#Modes">Respond to Changes Between Modes</a></li>
     13   <li><a href="#Drawing">Draw Your Watch Face</a></li>
     14 </ol>
     15 <h2>You should also read</h2>
     16 <ul>
     17   <li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li>
     18 </ul>
     19 <h2>Related Samples</h2>
     20   <ul>
     21     <li><a href="{@docRoot}samples/WatchFace/index.html">WatchFace</a></li>
     22   </ul>
     23 </div>
     24 </div>
     25 
     26 <p>After you have configured your project and added a class that implements the watch
     27 face service, you can start writing code to initialize and draw your custom watch face.</p>
     28 
     29 <p>This lesson includes examples from the
     30 <a href="{@docRoot}samples/WatchFace/index.html">WatchFace</a> sample to show how the system uses
     31 the watch face service. Many aspects of the
     32 service implementations described here (such as initialization and device features detection)
     33 apply to any watch face, so you can reuse some of the code in your own watch faces.</p>
     34 
     35 
     36 <img src="{@docRoot}training/wearables/watch-faces/images/preview_analog.png"
     37      width="180" height="180" alt="" style="margin-top:12px"/>
     38 <img src="{@docRoot}training/wearables/watch-faces/images/preview_digital.png"
     39      width="180" height="180" alt="" style="margin-left:25px;margin-top:12px"/>
     40 <p class="img-caption">
     41 <strong>Figure 1.</strong> The analog and digital watch faces in
     42 the
     43 <a href="{@docRoot}samples/WatchFace/index.html">WatchFace</a> sample.</p>
     44 
     45 
     46 <h2 id="Initialize">Initialize Your Watch Face</h2>
     47 
     48 <p>When the system loads your service, you should allocate and initialize most of the resources
     49 that your watch face needs, including loading bitmap resources, creating timer objects to run
     50 custom animations, configuring paint styles, and performing other computations. You can usually
     51 perform these operations only once and reuse their results. This practice improves the performance
     52 of your watch face and makes it easier to maintain your code.</p>
     53 
     54 <p>To initialize your watch face, follow these steps:</p>
     55 
     56 <ol>
     57 <li>Declare variables for a custom timer, graphic objects, and other elements.</li>
     58 <li>Initialize the watch face elements in the
     59 <a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onCreate(android.view.SurfaceHolder)"><code>Engine.onCreate()</code></a>
     60 method.</li>
     61 <li>Initialize the custom timer in the
     62 <a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onVisibilityChanged(boolean)"><code>Engine.onVisibilityChanged()</code></a>
     63 method.</li>
     64 </ol>
     65 
     66 <p>The following sections describe these steps in detail.</p>
     67 
     68 <h3 id="Variables">Declare variables</h3>
     69 
     70 <p>The resources that you intialize when the system loads your service need to be accessible
     71 at different points throughout your implementation, so you can reuse them. You achieve this
     72 by declaring member variables for these resources in your
     73 <a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html"><code>WatchFaceService.Engine</code></a>
     74 implementation.</p>
     75 
     76 <p>Declare variables for the following elements:</p>
     77 
     78 <dl>
     79 <dt><em>Graphic objects</em></dt>
     80 <dd>Most watch faces contain at least one bitmap image used as the background of the watch face,
     81 as described in
     82 <a href="{@docRoot}training/wearables/watch-faces/designing.html#ImplementationStrategy">Create an
     83 Implementation Strategy</a>. You can use additional bitmap images that represent clock hands or
     84 other design elements of your watch face.</dd>
     85 <dt><em>Periodic timer</em></dt>
     86 <dd>The system notifies the watch face once a minute when the time changes, but some watch faces
     87 run animations at custom time intervals. In these cases, you need to provide a custom timer that
     88 ticks with the frequency required to update your watch face.</dd>
     89 <dt><em>Time zone change receiver</em></dt>
     90 <dd>Users can adjust their time zone when they travel, and the system broadcasts this event.
     91 Your service implementation must register a broadcast receiver that is notified when the time
     92 zone changes and update the time accordingly.</dd>
     93 </dl>
     94 
     95 <p>The following snippet shows how to define these variables:</p>
     96 
     97 <pre>
     98 private class Engine extends CanvasWatchFaceService.Engine {
     99     static final int MSG_UPDATE_TIME = 0;
    100 
    101     Calendar mCalendar;
    102 
    103     // device features
    104     boolean mLowBitAmbient;
    105 
    106     // graphic objects
    107     Bitmap mBackgroundBitmap;
    108     Bitmap mBackgroundScaledBitmap;
    109     Paint mHourPaint;
    110     Paint mMinutePaint;
    111     ...
    112 
    113     // handler to update the time once a second in interactive mode
    114     final Handler mUpdateTimeHandler = new Handler() {
    115         &#64;Override
    116         public void handleMessage(Message message) {
    117             switch (message.what) {
    118                 case MSG_UPDATE_TIME:
    119                     invalidate();
    120                     if (shouldTimerBeRunning()) {
    121                         long timeMs = System.currentTimeMillis();
    122                         long delayMs = INTERACTIVE_UPDATE_RATE_MS
    123                                 - (timeMs % INTERACTIVE_UPDATE_RATE_MS);
    124                         mUpdateTimeHandler
    125                             .sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs);
    126                     }
    127                     break;
    128             }
    129         }
    130     };
    131 
    132     // receiver to update the time zone
    133     final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
    134         &#64;Override
    135         public void onReceive(Context context, Intent intent) {
    136             mCalendar.setTimeZone(TimeZone.getDefault());
    137             invalidate();
    138         }
    139     };
    140 
    141     // service methods (see other sections)
    142     ...
    143 }
    144 </pre>
    145 
    146 <p>In the example above, the custom timer is implemented as a
    147 {@link android.os.Handler} instance that sends and processes delayed messages using the thread's
    148 message queue. For this particular watch face, the custom timer ticks once every second. When the
    149 timer ticks, the handler calls the
    150 <a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#invalidate()"><code>invalidate()</code></a>
    151 method and the system then calls the
    152 <a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#onDraw(android.graphics.Canvas, android.graphics.Rect)"<code>onDraw()</code></a>
    153 method to redraw the watch face.</p>
    154 
    155 <h3 id="InitializeElements">Initialize watch face elements</h3>
    156 
    157 <p>After declaring member variables for bitmap resources, paint styles, and other
    158 elements that you reuse every time you redraw your watch face, initialize them when the system
    159 loads your service. Initializing these elements only once and reusing them improves performance
    160 and battery life.</p>
    161 
    162 <p>In the
    163 <a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onCreate(android.view.SurfaceHolder)"><code>Engine.onCreate()</code></a>
    164 method, initialize the following elements:</p>
    165 
    166 <ul>
    167 <li>Load the background image.</li>
    168 <li>Create styles and colors to draw graphic objects.</li>
    169 <li>Allocate an object to calculate the time.</li>
    170 <li>Configure the system UI.</li>
    171 </ul>
    172 
    173 <p>The following snippet shows how to initialize these elements:</p>
    174 
    175 <pre>
    176 &#64;Override
    177 public void onCreate(SurfaceHolder holder) {
    178     super.onCreate(holder);
    179 
    180     // configure the system UI (see next section)
    181     ...
    182 
    183     // load the background image
    184     Resources resources = AnalogWatchFaceService.this.getResources();
    185     Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg, null);
    186     mBackgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();
    187 
    188     // create graphic styles
    189     mHourPaint = new Paint();
    190     mHourPaint.setARGB(255, 200, 200, 200);
    191     mHourPaint.setStrokeWidth(5.0f);
    192     mHourPaint.setAntiAlias(true);
    193     mHourPaint.setStrokeCap(Paint.Cap.ROUND);
    194     ...
    195 
    196     // allocate a Calendar to calculate local time using the UTC time and time zone
    197     mCalendar = Calendar.getInstance();
    198 }
    199 </pre>
    200 
    201 <p>The background bitmap is loaded only once when the system initializes the watch face. The
    202 graphic styles are instances of the {@link android.graphics.Paint} class. Use these
    203 styles to draw the elements of your watch face inside the
    204 <a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#onDraw(android.graphics.Canvas, android.graphics.Rect)"><code>Engine.onDraw()</code></a>
    205 method, as described in <a href="#Drawing">Drawing Your Watch Face</a>.</p>
    206 
    207 <h3 id="Timer">Initialize the custom timer</h3>
    208 
    209 <p>As a watch face developer, you decide how often you want to update your watch face by
    210 providing a custom timer that ticks with the required frequency while the device is in
    211 interactive mode. This enables you to create custom animations and other visual effects.
    212 </p>
    213 
    214 <p class="note"><strong>Note:</strong> In ambient mode, the system does not reliably call the
    215 custom timer. To update the watch face in ambient mode, see <a href="#TimeTick">Update the watch
    216 face in ambient mode</a>.</p>
    217 
    218 <p>An example timer definition from the <code>AnalogWatchFaceService</code> class that ticks once
    219 every second is shown in <a href="#Variables">Declare variables</a>. In the
    220 <a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onVisibilityChanged(boolean)"><code>Engine.onVisibilityChanged()</code></a>
    221 method, start the custom timer if these two conditions apply:</p>
    222 
    223 <ul>
    224 <li>The watch face is visible.</li>
    225 <li>The device is in interactive mode.</li>
    226 </ul>
    227 
    228 <p>The <code>AnalogWatchFaceService</code> class schedules the next timer tick if required as
    229 follows:</p>
    230 
    231 <pre>
    232 private void updateTimer() {
    233     mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
    234     if (shouldTimerBeRunning()) {
    235         mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME);
    236     }
    237 }
    238 
    239 private boolean shouldTimerBeRunning() {
    240     return isVisible() &amp;&amp; !isInAmbientMode();
    241 }
    242 </pre>
    243 
    244 <p>This custom timer ticks once every second, as described in <a href="#Variables">Declare
    245 variables</a>.</p>
    246 
    247 <p>In the
    248 <a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onVisibilityChanged(boolean)"><code>onVisibilityChanged()</code></a>
    249 method, start the timer if required and register the receiver for time zone changes as follows:
    250 </p>
    251 
    252 <pre>
    253 &#64;Override
    254 public void onVisibilityChanged(boolean visible) {
    255     super.onVisibilityChanged(visible);
    256 
    257     if (visible) {
    258         registerReceiver();
    259 
    260         // Update time zone in case it changed while we weren't visible.
    261         mCalendar.setTimeZone(TimeZone.getDefault());
    262     } else {
    263         unregisterReceiver();
    264     }
    265 
    266     // Whether the timer should be running depends on whether we're visible and
    267     // whether we're in ambient mode, so we may need to start or stop the timer
    268     updateTimer();
    269 }
    270 </pre>
    271 
    272 <p>When the watch face is visible, the
    273 <a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onVisibilityChanged(boolean)"><code>onVisibilityChanged()</code></a>
    274 method registers the receiver for time zone changes. If the device is in interactive mode, this
    275 method also starts the custom timer. When the watch face is not visible, this
    276 method stops the custom timer and unregisters the receiver for time zone changes.
    277 The <code>registerReceiver()</code> and <code>unregisterReceiver()</code> methods are implemented as
    278 follows:</p>
    279 
    280 <pre>
    281 private void registerReceiver() {
    282     if (mRegisteredTimeZoneReceiver) {
    283         return;
    284     }
    285     mRegisteredTimeZoneReceiver = true;
    286     IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
    287     AnalogWatchFaceService.this.registerReceiver(mTimeZoneReceiver, filter);
    288 }
    289 
    290 private void unregisterReceiver() {
    291     if (!mRegisteredTimeZoneReceiver) {
    292         return;
    293     }
    294     mRegisteredTimeZoneReceiver = false;
    295     AnalogWatchFaceService.this.unregisterReceiver(mTimeZoneReceiver);
    296 }
    297 </pre>
    298 
    299 
    300 
    301 <h3 id="TimeTick">Update the watch face in ambient mode</h3>
    302 
    303 <p>In ambient mode, the system calls the
    304 <a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onTimeTick()"><code>Engine.onTimeTick()</code></a>
    305 method every minute. It is usually sufficient to update your watch face once per minute in this
    306 mode. To update your watch face while in interactive mode, you must provide a custom timer as
    307 described in <a href="#Timer">Initialize the custom timer</a>.</p>
    308 
    309 <p>In ambient mode, most watch face implementations simply invalidate the canvas to redraw the watch
    310 face in the
    311 <a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onTimeTick()"<code>Engine.onTimeTick()</code></a>
    312 method:</p>
    313 
    314 <pre>
    315 &#64;Override
    316 public void onTimeTick() {
    317     super.onTimeTick();
    318 
    319     invalidate();
    320 }
    321 </pre>
    322 
    323 
    324 
    325 <h2 id="SystemUI">Configure the System UI</h2>
    326 
    327 <p>Watch faces should not interfere with system UI elements, as described in
    328 <a href="{@docRoot}design/wear/watchfaces.html#SystemUI">Accommodate System UI Elements</a>.
    329 If your watch face has a light background or shows information near the bottom of the screen,
    330 you may have to configure the size of notification cards or enable background protection.</p>
    331 
    332 <p>Android Wear enables you to configure the following aspects of the system UI when your watch
    333 face is active:</p>
    334 
    335 <ul>
    336 <li>Specify how far the first notification card peeks into the screen.</li>
    337 <li>Specify whether the system draws the time over your watch face.</li>
    338 <li>Show or hide cards when in ambient mode.</li>
    339 <li>Protect the system indicators with a solid background around them.</li>
    340 <li>Specify the positioning of the system indicators.</li>
    341 </ul>
    342 
    343 <p>To configure these aspects of the system UI, create a
    344 <a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceStyle.html"><code>WatchFaceStyle</code></a>
    345 instance and pass it to the
    346 <a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#setWatchFaceStyle(android.support.wearable.watchface.WatchFaceStyle)"><code>Engine.setWatchFaceStyle()</code></a>
    347 method.</p>
    348 
    349 <p>The <code>AnalogWatchFaceService</code> class configures the system UI as follows:</p>
    350 
    351 <pre>
    352 &#64;Override
    353 public void onCreate(SurfaceHolder holder) {
    354     super.onCreate(holder);
    355 
    356     // configure the system UI
    357     setWatchFaceStyle(new WatchFaceStyle.Builder(AnalogWatchFaceService.this)
    358             .setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
    359             .setBackgroundVisibility(WatchFaceStyle
    360                                     .BACKGROUND_VISIBILITY_INTERRUPTIVE)
    361             .setShowSystemUiTime(false)
    362             .build());
    363     ...
    364 }
    365 </pre>
    366 
    367 <p>The code snippet above configures peeking cards to be a single line tall, the background
    368 of a peeking card to show only briefly and only for interruptive notifications, and the system
    369 time not to be shown (since this watch face draws its own time representation).</p>
    370 
    371 <p>You can configure the style of the system UI at any point in your watch face implementation.
    372 For example, if the user selects a white background, you can add background protection for the
    373 system indicators.</p>
    374 
    375 <p>For more details about configuring the system UI, see the
    376 <a href="{@docRoot}reference/packages-wearable-support.html">Wear API reference documentation</a>.
    377 </p>
    378 
    379 
    380 <h2 id="Screen">Obtain Information About the Device Screen</h2>
    381 
    382 <p>The system calls the
    383 <a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onPropertiesChanged(android.os.Bundle)"><code>Engine.onPropertiesChanged()</code></a>
    384 method when it determines the properties of the device screen, such as whether the device uses
    385 low-bit ambient mode and whether the screen requires burn-in protection.</p>
    386 
    387 <p>The following code snippet shows how to obtain these properties:</p>
    388 
    389 <pre>
    390 &#64;Override
    391 public void onPropertiesChanged(Bundle properties) {
    392     super.onPropertiesChanged(properties);
    393     mLowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
    394     mBurnInProtection = properties.getBoolean(PROPERTY_BURN_IN_PROTECTION,
    395             false);
    396 }
    397 </pre>
    398 
    399 <p>You should take these device properties into account when drawing your watch face:</p>
    400 
    401 <ul>
    402 <li>For devices that use low-bit ambient mode, the screen supports fewer bits for each color
    403 in ambient mode, so you should disable anti-aliasing and bitmap filtering when the device switches
    404 to ambient mode.</li>
    405 <li>For devices that require burn-in protection, avoid using large blocks of white pixels in
    406 ambient mode and do not place content within 10 pixels of the edge of the screen, since the
    407 system shifts the content periodically to avoid pixel burn-in.</li>
    408 </ul>
    409 
    410 <p>For more information about low-bit ambient mode and burn-in protection, see
    411 <a href="{@docRoot}design/wear/watchfaces.html#SpecialScreens">Optimize for Special
    412 Screens</a>. For more information on how to disable bitmap filtering, see
    413 <a href="{@docRoot}training/wearables/watch-faces/performance.html#BitmapFiltering">Bitmap
    414 Filtering</a>.</p>
    415 
    416 
    417 <h2 id="Modes">Respond to Changes Between Modes</h2>
    418 
    419 <p>When the device switches between ambient and interactive modes, the system calls the
    420 <a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onAmbientModeChanged(boolean)"><code>Engine.onAmbientModeChanged()</code></a>
    421 method. Your service implementation should make any necessary adjustments to switch between modes
    422 and then call the
    423 <a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#invalidate()"><code>invalidate()</code></a>
    424 method for the system to redraw the watch face.</p>
    425 
    426 <p>The following snippet shows how to implement this method:</p>
    427 
    428 <pre>
    429 &#64;Override
    430 public void onAmbientModeChanged(boolean inAmbientMode) {
    431 
    432     super.onAmbientModeChanged(inAmbientMode);
    433 
    434     if (mLowBitAmbient) {
    435         boolean antiAlias = !inAmbientMode;
    436         mHourPaint.setAntiAlias(antiAlias);
    437         mMinutePaint.setAntiAlias(antiAlias);
    438         mSecondPaint.setAntiAlias(antiAlias);
    439         mTickPaint.setAntiAlias(antiAlias);
    440     }
    441     invalidate();
    442     updateTimer();
    443 }
    444 </pre>
    445 
    446 <p>This example makes adjustments to some graphic styles and invalidates the canvas so the
    447 system can redraw the watch face.</p>
    448 
    449 
    450 
    451 <h2 id="Drawing">Draw Your Watch Face</h2>
    452 
    453 <p>To draw a custom watch face, the system calls the
    454 <a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#onDraw(android.graphics.Canvas, android.graphics.Rect)"><code>Engine.onDraw()</code></a>
    455 method with a {@link android.graphics.Canvas} instance and the bounds in which you should draw your
    456 watch face. The bounds take into account any inset areas, such as the "chin" on the bottom of some
    457 round devices. You can use this canvas to draw your watch face directly as follows:</p>
    458 
    459 <ol>
    460 <li>Override the
    461 <a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#onSurfaceChanged(android.view.SurfaceHolder, int, int, int)"><code>onSurfaceChanged()</code></a>
    462 method to scale your background to fit the device any time the view changes.
    463 <pre>
    464 &#64;Override
    465 public void onSurfaceChanged(
    466         SurfaceHolder holder, int format, int width, int height) {
    467     if (mBackgroundScaledBitmap == null
    468             || mBackgroundScaledBitmap.getWidth() != width
    469             || mBackgroundScaledBitmap.getHeight() != height) {
    470         mBackgroundScaledBitmap = Bitmap.createScaledBitmap(mBackgroundBitmap,
    471                 width, height, true /* filter */);
    472     }
    473     super.onSurfaceChanged(holder, format, width, height);
    474 }
    475 </pre>
    476 </li>
    477 <li>Check whether the device is in ambient mode or interactive mode.</li>
    478 <li>Perform any required graphic computations.</li>
    479 <li>Draw your background bitmap on the canvas.</li>
    480 <li>Use the methods in the {@link android.graphics.Canvas} class to draw your watch face.</li>
    481 </ol>
    482 
    483 <p>The following snippet shows how to implement the
    484 <a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#onDraw(android.graphics.Canvas, android.graphics.Rect)"><code>onDraw()</code></a>
    485 method:</p>
    486 
    487 <pre>
    488 &#64;Override
    489 public void onDraw(Canvas canvas, Rect bounds) {
    490     // Update the time
    491     mCalendar.setTimeInMillis(System.currentTimeMillis());
    492 
    493     // Constant to help calculate clock hand rotations
    494     final float TWO_PI = (float) Math.PI * 2f;
    495 
    496     int width = bounds.width();
    497     int height = bounds.height();
    498 
    499     canvas.drawBitmap(mBackgroundScaledBitmap, 0, 0, null);
    500 
    501     // Find the center. Ignore the window insets so that, on round watches
    502     // with a "chin", the watch face is centered on the entire screen, not
    503     // just the usable portion.
    504     float centerX = width / 2f;
    505     float centerY = height / 2f;
    506 
    507     // Compute rotations and lengths for the clock hands.
    508     float seconds = mCalendar.get(Calendar.SECOND) +
    509                     mCalendar.get(Calendar.MILLISECOND) / 1000f;
    510     float secRot = seconds / 60f * TWO_PI;
    511     float minutes = mCalendar.get(Calendar.MINUTE) + seconds / 60f;
    512     float minRot = minutes / 60f * TWO_PI;
    513     float hours = mCalendar.get(Calendar.HOUR) + minutes / 60f;
    514     float hrRot = hours / 12f * TWO_PI;
    515 
    516     float secLength = centerX - 20;
    517     float minLength = centerX - 40;
    518     float hrLength = centerX - 80;
    519 
    520     // Only draw the second hand in interactive mode.
    521     if (!isInAmbientMode()) {
    522         float secX = (float) Math.sin(secRot) * secLength;
    523         float secY = (float) -Math.cos(secRot) * secLength;
    524         canvas.drawLine(centerX, centerY, centerX + secX, centerY +
    525                         secY, mSecondPaint);
    526     }
    527 
    528     // Draw the minute and hour hands.
    529     float minX = (float) Math.sin(minRot) * minLength;
    530     float minY = (float) -Math.cos(minRot) * minLength;
    531     canvas.drawLine(centerX, centerY, centerX + minX, centerY + minY,
    532                     mMinutePaint);
    533     float hrX = (float) Math.sin(hrRot) * hrLength;
    534     float hrY = (float) -Math.cos(hrRot) * hrLength;
    535     canvas.drawLine(centerX, centerY, centerX + hrX, centerY + hrY,
    536                     mHourPaint);
    537 }
    538 </pre>
    539 
    540 <p>This method computes the required positions for the clock hands based on the current time
    541 and draws them on top of the background bitmap using the graphic styles initialized in the
    542 <a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onCreate(android.view.SurfaceHolder)"><code>onCreate()</code></a>
    543 method. The second hand is only drawn in interactive mode, not in ambient mode.</p>
    544 
    545 <p>For more information about drawing on a Canvas instance, see <a
    546 href="{@docRoot}guide/topics/graphics/2d-graphics.html">Canvas and Drawables</a>.</p>
    547 
    548 <p>The <a href="{@docRoot}samples/WatchFace/index.html">WatchFace</a> sample includes additional
    549 watch faces that you can refer to as examples of how to implement the
    550 <a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#onDraw(android.graphics.Canvas, android.graphics.Rect)"><code>onDraw()</code></a>
    551 method.</p>
    552