am d8b632fb: Merge "docs: Fix WatchFace guide to no longer reference deprecated Time.java Also fix links to samples and reference docs." into mnc-preview-docs

* commit 'd8b632fbce276ca0e91bf2b251aff266869e1291':
  docs: Fix WatchFace guide to no longer reference deprecated Time.java Also fix links to samples and reference docs.
This commit is contained in:
Luan Nguyen
2015-06-09 15:01:16 +00:00
committed by Android Git Automerger

View File

@ -16,17 +16,20 @@ page.title=Drawing Watch Faces
<ul>
<li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li>
</ul>
<h2>Related Samples</h2>
<ul>
<li><a href="{@docRoot}samples/WatchFace/index.html">WatchFace</a></li>
</ul>
</div>
</div>
<p>After you have configured your project and added a class that implements the watch
face service, you can start writing code to initialize and draw your custom watch face.</p>
<p>This lesson explains how the system invokes the methods in the
watch face service using examples from the <em>WatchFace</em> sample
included in the Android SDK. This sample is located in the
<code>android-sdk/samples/android-21/wearable/WatchFace</code> directory. Many aspects of the
service implementations described here (such as initialization and detecting device features)
<p>This lesson includes examples from the
<a href="{@docRoot}samples/WatchFace/index.html">WatchFace</a> sample to show how the system uses
the watch face service. Many aspects of the
service implementations described here (such as initialization and device features detection)
apply to any watch face, so you can reuse some of the code in your own watch faces.</p>
@ -36,7 +39,8 @@ apply to any watch face, so you can reuse some of the code in your own watch fac
width="180" height="180" alt="" style="margin-left:25px;margin-top:12px"/>
<p class="img-caption">
<strong>Figure 1.</strong> The analog and digital watch faces in
the <em>WatchFace</em> sample.</p>
the
<a href="{@docRoot}samples/WatchFace/index.html">WatchFace</a> sample.</p>
<h2 id="Initialize">Initialize Your Watch Face</h2>
@ -51,8 +55,12 @@ of your watch face and makes it easier to maintain your code.</p>
<ol>
<li>Declare variables for a custom timer, graphic objects, and other elements.</li>
<li>Initialize the watch face elements in the <code>Engine.onCreate()</code> method.</li>
<li>Initialize the custom timer in the <code>Engine.onVisibilityChanged()</code> method.</li>
<li>Initialize the watch face elements in the
<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onCreate(android.view.SurfaceHolder)"><code>Engine.onCreate()</code></a>
method.</li>
<li>Initialize the custom timer in the
<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onVisibilityChanged(boolean)"><code>Engine.onVisibilityChanged()</code></a>
method.</li>
</ol>
<p>The following sections describe these steps in detail.</p>
@ -61,7 +69,8 @@ of your watch face and makes it easier to maintain your code.</p>
<p>The resources that you intialize when the system loads your service need to be accessible
at different points throughout your implementation, so you can reuse them. You achieve this
by declaring member variables for these resources in your <code>WatchFaceService.Engine</code>
by declaring member variables for these resources in your
<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html"><code>WatchFaceService.Engine</code></a>
implementation.</p>
<p>Declare variables for the following elements:</p>
@ -83,31 +92,25 @@ Your service implementation must register a broadcast receiver that is notified
zone changes and update the time accordingly.</dd>
</dl>
<p>The <code>AnalogWatchFaceService.Engine</code> class in the <em>WatchFace</em> sample defines
these variables as shown in the snippet below. The custom timer is implemented as a
{@link android.os.Handler} instance that sends and processes delayed messages using the thread's
message queue. For this particular watch face, the custom timer ticks once every second. When the
timer ticks, the handler calls the <code>invalidate()</code> method and the system then calls
the <code>onDraw()</code> method to redraw the watch face.</p>
<p>The following snippet shows how to define these variables:</p>
<pre>
private class Engine extends CanvasWatchFaceService.Engine {
static final int MSG_UPDATE_TIME = 0;
/* a time object */
Time mTime;
Calendar mCalendar;
/* device features */
// device features
boolean mLowBitAmbient;
/* graphic objects */
// graphic objects
Bitmap mBackgroundBitmap;
Bitmap mBackgroundScaledBitmap;
Paint mHourPaint;
Paint mMinutePaint;
...
/* handler to update the time once a second in interactive mode */
// handler to update the time once a second in interactive mode
final Handler mUpdateTimeHandler = new Handler() {
&#64;Override
public void handleMessage(Message message) {
@ -126,53 +129,63 @@ private class Engine extends CanvasWatchFaceService.Engine {
}
};
/* receiver to update the time zone */
// receiver to update the time zone
final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
&#64;Override
public void onReceive(Context context, Intent intent) {
mTime.clear(intent.getStringExtra("time-zone"));
mTime.setToNow();
mCalendar.setTimeZone(TimeZone.getDefault());
invalidate();
}
};
/* service methods (see other sections) */
// service methods (see other sections)
...
}
</pre>
<p>In the example above, the custom timer is implemented as a
{@link android.os.Handler} instance that sends and processes delayed messages using the thread's
message queue. For this particular watch face, the custom timer ticks once every second. When the
timer ticks, the handler calls the
<a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#invalidate()"><code>invalidate()</code></a>
method and the system then calls the
<a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#onDraw(android.graphics.Canvas, android.graphics.Rect)"<code>onDraw()</code></a>
method to redraw the watch face.</p>
<h3 id="InitializeElements">Initialize watch face elements</h3>
<p>After you have declared member variables for bitmap resources, paint styles, and other
elements that you reuse every time your redraw your watch face, initialize them when the system
<p>After declaring member variables for bitmap resources, paint styles, and other
elements that you reuse every time you redraw your watch face, initialize them when the system
loads your service. Initializing these elements only once and reusing them improves performance
and battery life.</p>
<p>In the <code>Engine.onCreate()</code> method, initialize the following elements:</p>
<p>In the
<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onCreate(android.view.SurfaceHolder)"><code>Engine.onCreate()</code></a>
method, initialize the following elements:</p>
<ul>
<li>Load the background image.</li>
<li>Create styles and colors to draw graphic objects.</li>
<li>Allocate an object to hold the time.</li>
<li>Allocate an object to calculate the time.</li>
<li>Configure the system UI.</li>
</ul>
<p>The <code>Engine.onCreate()</code> method in the <code>AnalogWatchFaceService</code> class
initializes these elements as follows:</p>
<p>The following snippet shows how to initialize these elements:</p>
<pre>
&#64;Override
public void onCreate(SurfaceHolder holder) {
super.onCreate(holder);
/* configure the system UI (see next section) */
// configure the system UI (see next section)
...
/* load the background image */
// load the background image
Resources resources = AnalogWatchFaceService.this.getResources();
Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg);
Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg, null);
mBackgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();
/* create graphic styles */
// create graphic styles
mHourPaint = new Paint();
mHourPaint.setARGB(255, 200, 200, 200);
mHourPaint.setStrokeWidth(5.0f);
@ -180,15 +193,16 @@ public void onCreate(SurfaceHolder holder) {
mHourPaint.setStrokeCap(Paint.Cap.ROUND);
...
/* allocate an object to hold the time */
mTime = new Time();
// allocate a Calendar to calculate local time using the UTC time and time zone
mCalendar = Calendar.getInstance();
}
</pre>
<p>The background bitmap is loaded only once when the system initializes the watch face. The
graphic styles are instances of the {@link android.graphics.Paint} class. You later use these
styles to draw the elements of your watch face inside the <code>Engine.onDraw()</code> method,
as described in <a href="#Drawing">Drawing Your Watch Face</a>.</p>
graphic styles are instances of the {@link android.graphics.Paint} class. Use these
styles to draw the elements of your watch face inside the
<a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#onDraw(android.graphics.Canvas, android.graphics.Rect)"><code>Engine.onDraw()</code></a>
method, as described in <a href="#Drawing">Drawing Your Watch Face</a>.</p>
<h3 id="Timer">Initialize the custom timer</h3>
@ -203,8 +217,8 @@ face in ambient mode</a>.</p>
<p>An example timer definition from the <code>AnalogWatchFaceService</code> class that ticks once
every second is shown in <a href="#Variables">Declare variables</a>. In the
<code>Engine.onVisibilityChanged()</code> method, start the custom timer if these two
conditions apply:</p>
<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onVisibilityChanged(boolean)"><code>Engine.onVisibilityChanged()</code></a>
method, start the custom timer if these two conditions apply:</p>
<ul>
<li>The watch face is visible.</li>
@ -230,8 +244,10 @@ private boolean shouldTimerBeRunning() {
<p>This custom timer ticks once every second, as described in <a href="#Variables">Declare
variables</a>.</p>
<p>In the <code>Engine.onVisibilityChanged()</code> method, start the timer if required and
and register the receiver for time zone changes as follows:</p>
<p>In the
<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onVisibilityChanged(boolean)"><code>onVisibilityChanged()</code></a>
method, start the timer if required and register the receiver for time zone changes as follows:
</p>
<pre>
&#64;Override
@ -242,23 +258,24 @@ public void onVisibilityChanged(boolean visible) {
registerReceiver();
// Update time zone in case it changed while we weren't visible.
mTime.clear(TimeZone.getDefault().getID());
mTime.setToNow();
mCalendar.setTimeZone(TimeZone.getDefault());
} else {
unregisterReceiver();
}
// Whether the timer should be running depends on whether we're visible and
// whether we're in ambient mode), so we may need to start or stop the timer
// whether we're in ambient mode, so we may need to start or stop the timer
updateTimer();
}
</pre>
<p>When the watch face is visible, the <code>onVisibilityChanged()</code> method registers
the receiver for time zone changes and starts the custom timer if the device is in interactive
mode. When the watch face is not visible, this method stops the custom timer and unregisters
the receiver for time zone changes. The <code>registerReceiver()</code> and
<code>unregisterReceiver()</code> methods are implemented as follows:</p>
<p>When the watch face is visible, the
<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onVisibilityChanged(boolean)"><code>onVisibilityChanged()</code></a>
method registers the receiver for time zone changes. If the device is in interactive mode, this
method also starts the custom timer. When the watch face is not visible, this
method stops the custom timer and unregisters the receiver for time zone changes.
The <code>registerReceiver()</code> and <code>unregisterReceiver()</code> methods are implemented as
follows:</p>
<pre>
private void registerReceiver() {
@ -283,13 +300,16 @@ private void unregisterReceiver() {
<h3 id="TimeTick">Update the watch face in ambient mode</h3>
<p>In ambient mode, the system calls the <code>Engine.onTimeTick()</code> method every minute.
It is usually sufficient to update your watch face once per minute in this mode. To update your
watch face while in interactive mode, you must provide a custom timer as described in
<a href="#Timer">Initialize the custom timer</a>.</p>
<p>In ambient mode, the system calls the
<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onTimeTick()"><code>Engine.onTimeTick()</code></a>
method every minute. It is usually sufficient to update your watch face once per minute in this
mode. To update your watch face while in interactive mode, you must provide a custom timer as
described in <a href="#Timer">Initialize the custom timer</a>.</p>
<p>In ambient mode, most watch face implementations simply invalidate the canvas to redraw the watch
face in the <code>Engine.onTimeTick()</code> method:</p>
face in the
<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onTimeTick()"<code>Engine.onTimeTick()</code></a>
method:</p>
<pre>
&#64;Override
@ -320,8 +340,11 @@ face is active:</p>
<li>Specify the positioning of the system indicators.</li>
</ul>
<p>To configure these aspects of the system UI, create a <code>WatchFaceStyle</code> instance
and pass it to the <code>Engine.setWatchFaceStyle()</code> method.</p>
<p>To configure these aspects of the system UI, create a
<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceStyle.html"><code>WatchFaceStyle</code></a>
instance and pass it to the
<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#setWatchFaceStyle(android.support.wearable.watchface.WatchFaceStyle)"><code>Engine.setWatchFaceStyle()</code></a>
method.</p>
<p>The <code>AnalogWatchFaceService</code> class configures the system UI as follows:</p>
@ -330,7 +353,7 @@ and pass it to the <code>Engine.setWatchFaceStyle()</code> method.</p>
public void onCreate(SurfaceHolder holder) {
super.onCreate(holder);
/* configure the system UI */
// configure the system UI
setWatchFaceStyle(new WatchFaceStyle.Builder(AnalogWatchFaceService.this)
.setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
.setBackgroundVisibility(WatchFaceStyle
@ -350,16 +373,16 @@ For example, if the user selects a white background, you can add background prot
system indicators.</p>
<p>For more details about configuring the system UI, see the
<a href="{@docRoot}shareables/training/wearable-support-docs.zip">API reference</a> for the
<code>WatchFaceStyle</code> class.</p>
<a href="{@docRoot}reference/packages-wearable-support.html">Wear API reference documentation</a>.
</p>
<h2 id="Screen">Obtain Information About the Device Screen</h2>
<p>The system calls the <code>Engine.onPropertiesChanged()</code> method when it determines
the properties of the device screen, such as whether the device uses low-bit ambient mode and
whether the screen requires burn-in protection.</p>
<p>The system calls the
<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onPropertiesChanged(android.os.Bundle)"><code>Engine.onPropertiesChanged()</code></a>
method when it determines the properties of the device screen, such as whether the device uses
low-bit ambient mode and whether the screen requires burn-in protection.</p>
<p>The following code snippet shows how to obtain these properties:</p>
@ -394,12 +417,13 @@ Filtering</a>.</p>
<h2 id="Modes">Respond to Changes Between Modes</h2>
<p>When the device switches between ambient and interactive modes, the system calls the
<code>Engine.onAmbientModeChanged()</code> method. Your service implementation should make
any necessary adjustments to switch between modes and then call the <code>invalidate()</code>
<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onAmbientModeChanged(boolean)"><code>Engine.onAmbientModeChanged()</code></a>
method. Your service implementation should make any necessary adjustments to switch between modes
and then call the
<a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#invalidate()"><code>invalidate()</code></a>
method for the system to redraw the watch face.</p>
<p>The following snippet shows how this method is implemented in the
<code>AnalogWatchFaceService</code> class inside the <em>WatchFace</em> sample:</p>
<p>The following snippet shows how to implement this method:</p>
<pre>
&#64;Override
@ -426,28 +450,34 @@ system can redraw the watch face.</p>
<h2 id="Drawing">Draw Your Watch Face</h2>
<p>To draw a custom watch face, the system calls the <code>Engine.onDraw()</code> method with a
{@link android.graphics.Canvas} instance and the bounds in which you should draw your watch face.
The bounds account for any inset areas, such as the "chin" on the bottom of some round devices.
You can use this canvas to draw your watch face directly as follows:</p>
<p>To draw a custom watch face, the system calls the
<a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#onDraw(android.graphics.Canvas, android.graphics.Rect)"><code>Engine.onDraw()</code></a>
method with a {@link android.graphics.Canvas} instance and the bounds in which you should draw your
watch face. The bounds take into account any inset areas, such as the "chin" on the bottom of some
round devices. You can use this canvas to draw your watch face directly as follows:</p>
<ol>
<li>If this is the first invocation of the <code>onDraw()</code> method, scale your background
to fit.</li>
<li>If this is the first invocation of the
<a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#onDraw(android.graphics.Canvas, android.graphics.Rect)"><code>onDraw()</code></a>
method, scale your background to fit.</li>
<li>Check whether the device is in ambient mode or interactive mode.</li>
<li>Perform any required graphic computations.</li>
<li>Draw your background bitmap on the canvas.</li>
<li>Use the methods in the {@link android.graphics.Canvas} class to draw your watch face.</li>
</ol>
<p>The <code>AnalogWatchFaceService</code> class in the <em>WatchFace</em> sample follows these
steps to implement the <code>onDraw()</code> method as follows:</p>
<p>The following snippet shows how to implement the
<a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#onDraw(android.graphics.Canvas, android.graphics.Rect)"><code>onDraw()</code></a>
method:</p>
<pre>
&#64;Override
public void onDraw(Canvas canvas, Rect bounds) {
// Update the time
mTime.setToNow();
mCalendar.setTimeInMillis(System.currentTimeMillis());
// Constant to help calculate clock hand rotations
final float TWO_PI = (float) Math.PI * 2f;
int width = bounds.width();
int height = bounds.height();
@ -457,7 +487,7 @@ public void onDraw(Canvas canvas, Rect bounds) {
|| mBackgroundScaledBitmap.getWidth() != width
|| mBackgroundScaledBitmap.getHeight() != height) {
mBackgroundScaledBitmap = Bitmap.createScaledBitmap(mBackgroundBitmap,
width, height, true /* filter */);
width, height, true);
}
canvas.drawBitmap(mBackgroundScaledBitmap, 0, 0, null);
@ -468,10 +498,13 @@ public void onDraw(Canvas canvas, Rect bounds) {
float centerY = height / 2f;
// Compute rotations and lengths for the clock hands.
float secRot = mTime.second / 30f * (float) Math.PI;
int minutes = mTime.minute;
float minRot = minutes / 30f * (float) Math.PI;
float hrRot = ((mTime.hour + (minutes / 60f)) / 6f ) * (float) Math.PI;
float seconds = mCalendar.get(Calendar.SECOND) +
mCalendar.get(Calendar.MILLISECOND) / 1000f;
float secRot = seconds / 60f * TWO_PI;
float minutes = mCalendar.get(Calendar.MINUTE) + seconds / 60f;
float minRot = minutes / 60f * TWO_PI;
float hours = mCalendar.get(Calendar.HOUR) + minutes / 60f;
float hrRot = hours / 12f * TWO_PI;
float secLength = centerX - 20;
float minLength = centerX - 40;
@ -499,11 +532,13 @@ public void onDraw(Canvas canvas, Rect bounds) {
<p>This method computes the required positions for the clock hands based on the current time
and draws them on top of the background bitmap using the graphic styles initialized in the
<code>onCreate()</code> method. The second hand is only drawn in interactive mode, not in
ambient mode.</p>
<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onCreate(android.view.SurfaceHolder)"><code>onCreate()</code></a>
method. The second hand is only drawn in interactive mode, not in ambient mode.</p>
<p>For more information about drawing on a Canvas instance, see <a
href="{@docRoot}guide/topics/graphics/2d-graphics.html">Canvas and Drawables</a>.</p>
<p>The <em>WatchFace</em> sample in the Android SDK includes additional watch faces that you
can refer to as examples of how to implement the <code>onDraw()</code> method.</p>
<p>The <a href="{@docRoot}samples/WatchFace/index.html">WatchFace</a> sample includes additional
watch faces that you can refer to as examples of how to implement the
<a href="{@docRoot}reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#onDraw(android.graphics.Canvas, android.graphics.Rect)"><code>onDraw()</code></a>
method.</p>