Merge "docs: Creating Custom Watch Faces training class." into lmp-docs

This commit is contained in:
Ricardo Cervera
2014-12-10 05:28:32 +00:00
committed by Android (Google) Code Review
23 changed files with 1633 additions and 0 deletions

View File

@@ -834,6 +834,38 @@ include the action bar on devices running Android 2.1 or higher."
</li>
</ul>
</li>
<li class="nav-section">
<div class="nav-section-header">
<a href="<?cs var:toroot ?>training/wearables/watch-faces/index.html"
description="How to create custom watch faces for wearables."
>Creating Custom Watch Faces</a>
</div>
<ul>
<li>
<a href="<?cs var:toroot ?>training/wearables/watch-faces/designing.html">Designing Watch Faces</a>
</li>
<li>
<a href="<?cs var:toroot ?>training/wearables/watch-faces/service.html">Building a Watch Face Service</a>
</li>
<li>
<a href="<?cs var:toroot ?>training/wearables/watch-faces/drawing.html">Drawing Watch Faces</a>
</li>
<li>
<a href="<?cs var:toroot ?>training/wearables/watch-faces/information.html">Showing Information in Watch Faces</a>
</li>
<li>
<a href="<?cs var:toroot ?>training/wearables/watch-faces/configuration.html">Providing Configuration Activities</a>
</li>
<li>
<a href="<?cs var:toroot ?>training/wearables/watch-faces/issues.html">Addressing Common Issues</a>
</li>
<li>
<a href="<?cs var:toroot ?>training/wearables/watch-faces/performance.html">Optimizing Performance and Battery Life</a>
</li>
</ul>
</li>
<li>
<a href="<?cs var:toroot ?>training/articles/wear-location-detection.html"
description=

View File

@@ -0,0 +1,144 @@
page.title=Providing Configuration Activities
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#Intent">Specify an Intent for Configuration Activities</a></li>
<li><a href="#WearableActivity">Create a Wearable Configuration Activity</a></li>
<li><a href="#CompanionActivity">Create a Companion Configuration Activity</a></li>
</ol>
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li>
</ul>
</div>
</div>
<p>When users install a handheld app that contains a <a
href="{@docRoot}training/wearables/apps/index.html">wearable app</a> with watch faces, these
watch faces become available in the Android Wear companion app on the companion device and in
the watch face picker on the wearable. Users can choose the active watch face for their wearable
device by selecting it on the companion app or using the watch face picker on the wearable
device.</p>
<p>Some watch faces support configuration parameters to let users customize how the watch face
looks and behaves. For example, some watch faces let users pick a custom background color, and
watch faces that tell time for two different time zones can let users select which time zones
they are interested in.</p>
<p>Watch faces that support configuration parameters can let users customize a watch face using
an activity in the wearable app, an activity on the handheld app, or both. Users can start the
wearable configuration activity on the wearable device, and they can start the companion
configuration activity from the Android Wear companion app.</p>
<p>The digital watch face from the <em>WatchFace</em> sample in the Android SDK demonstrates how to
implement handheld and wearable configuration activities and how to update a watch face in
response to configuration changes. This sample is located in the
<code>android-sdk/samples/android-21/wearable/WatchFace</code> directory.</p>
<h2 id="Intent">Specify an Intent for Configuration Activities</h2>
<p>If your watch face includes configuration activities, add the following metadata entries to
the service declaration in the manifest file of the wearable app:</p>
<pre>
&lt;service
android:name=".DigitalWatchFaceService" ... />
&lt;!-- companion configuration activity -->
&lt;meta-data
android:name=
"com.google.android.wearable.watchface.companionConfigurationAction"
android:value=
"com.example.android.wearable.watchface.CONFIG_DIGITAL" />
&lt;!-- wearable configuration activity -->
&lt;meta-data
android:name=
"com.google.android.wearable.watchface.wearableConfigurationAction"
android:value=
"com.example.android.wearable.watchface.CONFIG_DIGITAL" />
...
&lt;/service>
</pre>
<p>Provide values for these entries that are preceded by the package name of your app.
Configuration activities register intent filters for this intent, and the system fires this
intent when users want to configure your watch face.</p>
<p>If your watch face only includes a companion or a wearable configuration activity, you only
need to include the corresponding metadata entry from the example above.</p>
<h2 id="WearableActivity">Create a Wearable Configuration Activity</h2>
<p>Wearable configuration activities provide a limited set of customization choices for a
watch face, because complex menus are hard to navigate on smaller screens. Your wearable
configuration activity should provide binary choices and just a few selections to customize
the main aspects of your watch face.</p>
<p>To create a wearable configuration activity, add a new activity to your wearable app module
and declare the following intent filter in the manifest file of the wearable app:</p>
<pre>
&lt;activity
android:name=".DigitalWatchFaceWearableConfigActivity"
android:label="@string/digital_config_name">
&lt;intent-filter>
&lt;action android:name=
"com.example.android.wearable.watchface.CONFIG_DIGITAL" />
&lt;category android:name=
"com.google.android.wearable.watchface.category.WEARABLE_CONFIGURATION" />
&lt;category android:name="android.intent.category.DEFAULT" />
&lt;/intent-filter>
&lt;/activity>
</pre>
<p>The name of the action in this intent filter must match the intent name you defined in
<a href="#Intent">Specify an Intent for Configuration Activities</a>.</p>
<p>In your configuration activity, build a simple UI that provides selections for users to
customize your watch face. When users make a selection, use the <a
href="{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer API</a> to
communicate the configuration change to the watch face activity.</p>
<p>For more details, see the <code>DigitalWatchFaceWearableConfigActivity</code> and
<code>DigitalWatchFaceUtil</code> classes in the <em>WatchFace</em> sample.</p>
<h2 id="CompanionActivity">Create a Companion Configuration Activity</h2>
<p>Companion configuration activities give users access to the full set of configuration choices
for a watch face, because it is easier to interact with complex menus on the larger screen of
a handheld device. For example, a configuration activity on a handheld device enables you to
present users with elaborate color pickers to select the background color of a watch face.</p>
<p>To create a companion configuration activity, add a new activity to your handheld app module and
declare the same intent filter for this activity as the one in <a href="#WearableActivity">Create
a Wearable Configuration Activity</a>.</p>
<p>In your configuration activity, build a UI that provides options to customize all the
configurable elements of your watch face. When users make a selection, use the <a
href="{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer API</a> to
communicate the configuration change to the watch face activity.</p>
<p>For more details, see the <code>DigitalWatchFaceCompanionConfigActivity</code> class in the
<em>WatchFace</em> sample.</p>
<h2 id="Listener">Create a Listener Service in the Wearable App</h2>
<p>To receive updated configuration parameters from the configuration activities, create a
service that implements the <code>WearableListenerService</code> interface from the <a
href="{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer API</a> in your
wearable app. Your watch face implementation can redraw the watch face when the configuration
parameters change.</p>
<p>For more details, see the <code>DigitalWatchFaceConfigListenerService</code> and
<code>DigitalWatchFaceService</code> classes in the <em>WatchFace</em> sample.</p>

View File

@@ -0,0 +1,108 @@
page.title=Designing Watch Faces
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#DesignGuidelines">Conform to the Design Guidelines</a></li>
<li><a href="#ImplementationStrategy">Create an Implementation Strategy</a></li>
</ol>
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li>
</ul>
</div>
</div>
<p>Similar to the process of designing a traditional watch face, creating one for
Android Wear is an exercise in visualizing time clearly. Android Wear devices
provide advanced capabilities for watch faces that you can leverage in your designs, such as
vibrant colors, dynamic backgrounds, animations, and data integration. However, there are
also many design considerations that you must take into account.</p>
<p>This lesson provides a summary of the design considerations for watch faces and general
guidelines to get started implementing a design. For more information, read the <a
href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a> design guide.</p>
<h2 id="DesignGuidelines">Conform to the Design Guidelines</h2>
<p>As you plan the look of your watch face and what kind of information it should present
to users, consider these design guidelines:</p>
<div style="float:right;margin-top:-5px;margin-left:20px">
<img src="{@docRoot}training/wearables/watch-faces/images/Render_Next.png"
width="200" height="195" alt="" style="margin-right:5px"/><br>
<img src="{@docRoot}training/wearables/watch-faces/images/Render_Interactive.png"
width="200" height="195" alt="" style="margin-right:5px"/>
<p class="img-caption" style="margin-top:0px;margin-left:10px">
<strong>Figure 1.</strong> Example watch faces.</p>
</div>
<dl>
<dt><em>Plan for square and round devices</em></dt>
<dd>Your design should work for both square and round Android Wear devices, including devices with
<a href="{@docRoot}training/wearables/ui/layouts.html#same-layout">insets on the bottom of the
screen</a>.</dd>
<dt><em>Support all display modes</em></dt>
<dd>Your watch face should support ambient mode with limited color and interactive mode with
full color and animations.</dd>
<dt><em>Optimize for special screen technologies</em></dt>
<dd>In ambient mode, your watch face should keep most pixels black. Depending on the screen
technology, you may need to avoid large blocks of white pixels, use only black and white, and
disable anti-aliasing.</dd>
<dt><em>Accomodate system UI elements</em></dt>
<dd>Your design should ensure that system indicators remain visible and that users can still
read the time when notification cards appear on the screen.</dd>
<dt><em>Integrate data</em></dt>
<dd>Your watch face can leverage sensors and cellular connectivity on the companion mobile
device to show user data relevant to the context, such as the weather for the day or their next
calendar event.</dd>
<dt><em>Provide configuration options</em></dt>
<dd>You can let users configure some aspects of your design (like colors and sizes) on the
wearable or on the Android Wear companion app.</dd>
</dl>
<p>For more information about designing watch faces for Android Wear, see the <a
href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a> design guide.</p>
<h2 id="ImplementationStrategy">Create an Implementation Strategy</h2>
<p>After you finalize the design for your watch face, you need to determine how to obtain any
necessary data and draw the watch face on the wearable device. Most implementations
consist of the following components:</p>
<ul>
<li>One or more background images</li>
<li>Application code to retrieve the required data</li>
<li>Application code to draw text and shapes over the background images</li>
</ul>
<p>You typically use one background image in interactive mode and a different background image
in ambient mode. The background in ambient mode is often completely black. Background images for
Android Wear devices with a screen density of hdpi should be 320 by 320 pixels in size to fit
both square and round devices. The corners of the background image are not visible on round
devices. In your code, you can detect the size of the device screen and scale down the background
image if the device has a lower resolution than your image. To improve performance, you should
scale the background image only once and store the resulting bitmap.</p>
<p>You should run the application code to retrieve contextual data only as often as required
and store the results to reuse the data every time you draw the watch face. For example, you
don't need to fetch weather updates every minute.</p>
<p>To increase battery life, the application code that draws your watch face in ambient mode
should be relatively simple. You usually draw outlines of shapes using a limited set of colors
in this mode. In interactive mode, you can use full color, complex shapes, gradients, and
animations to draw your watch face.</p>
<p>The remaining lessons in this class show you how to implement watch faces in detail.</p>

View File

@@ -0,0 +1,509 @@
page.title=Drawing Watch Faces
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#Initialize">Initialize Your Watch Face</a></li>
<li><a href="#SystemUI">Configure the System UI</a></li>
<li><a href="#Screen">Obtain Information About the Device Screen</a></li>
<li><a href="#Modes">Respond to Changes Between Modes</a></li>
<li><a href="#Drawing">Draw Your Watch Face</a></li>
</ol>
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</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)
apply to any watch face, so you can reuse some of the code in your own watch faces.</p>
<img src="{@docRoot}training/wearables/watch-faces/images/preview_analog.png"
width="180" height="180" alt="" style="margin-top:12px"/>
<img src="{@docRoot}training/wearables/watch-faces/images/preview_digital.png"
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>
<h2 id="Initialize">Initialize Your Watch Face</h2>
<p>When the system loads your service, you should allocate and initialize most of the resources
that your watch face needs, including loading bitmap resources, creating timer objects to run
custom animations, configuring paint styles, and performing other computations. You can usually
perform these operations only once and reuse their results. This practice improves the performance
of your watch face and makes it easier to maintain your code.</p>
<p>To initialize your watch face, follow these steps:</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>
</ol>
<p>The following sections describe these steps in detail.</p>
<h3 id="Variables">Declare variables</h3>
<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>
implementation.</p>
<p>Declare variables for the following elements:</p>
<dl>
<dt><em>Graphic objects</em></dt>
<dd>Most watch faces contain at least one bitmap image used as the background of the watch face,
as described in
<a href="{@docRoot}training/wearables/watch-faces/designing.html#ImplementationStrategy">Create an
Implementation Strategy</a>. You can use additional bitmap images that represent clock hands or
other design elements of your watch face.</dd>
<dt><em>Periodic timer</em></dt>
<dd>The system notifies the watch face once a minute when the time changes, but some watch faces
run animations at custom time intervals. In these cases, you need to provide a custom timer that
ticks with the frequency required to update your watch face.</dd>
<dt><em>Time zone change receiver</em></dt>
<dd>Users can adjust their time zone when they travel, and the system broadcasts this event.
Your service implementation must register a broadcast receiver that is notified when the time
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>
<pre>
private class Engine extends CanvasWatchFaceService.Engine {
static final int MSG_UPDATE_TIME = 0;
/* a time object */
Time mTime;
/* device features */
boolean mLowBitAmbient;
/* graphic objects */
Bitmap mBackgroundBitmap;
Bitmap mBackgroundScaledBitmap;
Paint mHourPaint;
Paint mMinutePaint;
...
/* handler to update the time once a second in interactive mode */
final Handler mUpdateTimeHandler = new Handler() {
&#64;Override
public void handleMessage(Message message) {
switch (message.what) {
case MSG_UPDATE_TIME:
invalidate();
if (shouldTimerBeRunning()) {
long timeMs = System.currentTimeMillis();
long delayMs = INTERACTIVE_UPDATE_RATE_MS
- (timeMs % INTERACTIVE_UPDATE_RATE_MS);
mUpdateTimeHandler
.sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs);
}
break;
}
}
};
/* 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();
}
};
/* service methods (see other sections) */
...
}
</pre>
<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
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>
<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>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>
<pre>
&#64;Override
public void onCreate(SurfaceHolder holder) {
super.onCreate(holder);
/* configure the system UI (see next section) */
...
/* load the background image */
Resources resources = AnalogWatchFaceService.this.getResources();
Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg);
mBackgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();
/* create graphic styles */
mHourPaint = new Paint();
mHourPaint.setARGB(255, 200, 200, 200);
mHourPaint.setStrokeWidth(5.0f);
mHourPaint.setAntiAlias(true);
mHourPaint.setStrokeCap(Paint.Cap.ROUND);
...
/* allocate an object to hold the time */
mTime = new Time();
}
</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>
<h3 id="Timer">Initialize the custom timer</h3>
<p>As a watch face developer, you can decide how often you want to update your watch face by
providing a custom timer that ticks with the required frequency while the device is in
interactive mode. This enables you to create custom animations and other visual effects. In
ambient mode, you should disable the timer to let the CPU sleep and update the watch face
only when the time changes. For more information, see
<a href="{@docRoot}training/wearables/watch-faces/performance.html">Optimizing Performance and
Battery Life</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>
<ul>
<li>The watch face is visible.</li>
<li>The device is in interactive mode.</li>
</ul>
<p>The timer should not run under any other conditions, since this watch face does not
draw the second hand in ambient mode to conserve power. The <code>AnalogWatchFaceService</code>
class schedules the next timer tick if required as follows:</p>
<pre>
private void updateTimer() {
mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
if (shouldTimerBeRunning()) {
mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME);
}
}
private boolean shouldTimerBeRunning() {
return isVisible() &amp;&amp; !isInAmbientMode();
}
</pre>
<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>
<pre>
&#64;Override
public void onVisibilityChanged(boolean visible) {
super.onVisibilityChanged(visible);
if (visible) {
registerReceiver();
// Update time zone in case it changed while we weren't visible.
mTime.clear(TimeZone.getDefault().getID());
mTime.setToNow();
} 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
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>
<pre>
private void registerReceiver() {
if (mRegisteredTimeZoneReceiver) {
return;
}
mRegisteredTimeZoneReceiver = true;
IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
AnalogWatchFaceService.this.registerReceiver(mTimeZoneReceiver, filter);
}
private void unregisterReceiver() {
if (!mRegisteredTimeZoneReceiver) {
return;
}
mRegisteredTimeZoneReceiver = false;
AnalogWatchFaceService.this.unregisterReceiver(mTimeZoneReceiver);
}
</pre>
<h3 id="TimeTick">Invalidate the canvas when the time changes</h3>
<p>The system calls the <code>Engine.onTimeTick()</code> method every minute. In ambient mode,
it is usually sufficient to update your watch face once per minute. To update your watch face
more often while in interactive mode, you provide a custom timer as described in
<a href="#Timer">Initialize the custom timer</a>.</p>
<p>Most watch face implementations just invalidate the canvas to redraw the watch face when
the time changes:</p>
<pre>
&#64;Override
public void onTimeTick() {
super.onTimeTick();
invalidate();
}
</pre>
<h2 id="SystemUI">Configure the System UI</h2>
<p>Watch faces should not interfere with system UI elements, as described in
<a href="{@docRoot}design/wear/watchfaces.html#SystemUI">Accommodate System UI Elements</a>.
If your watch face has a light background or shows information near the bottom of the screen,
you may have to configure the size of notification cards or enable background protection.</p>
<p>Android Wear enables you to configure the following aspects of the system UI when your watch
face is active:</p>
<ul>
<li>Specify how far the first notification card peeks into the screen.</li>
<li>Specify whether the system draws the time over your watch face.</li>
<li>Show or hide cards when in ambient mode.</li>
<li>Protect the system indicators with a solid background around them.</li>
<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>The <code>AnalogWatchFaceService</code> class configures the system UI as follows:</p>
<pre>
&#64;Override
public void onCreate(SurfaceHolder holder) {
super.onCreate(holder);
/* configure the system UI */
setWatchFaceStyle(new WatchFaceStyle.Builder(AnalogWatchFaceService.this)
.setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
.setBackgroundVisibility(WatchFaceStyle
.BACKGROUND_VISIBILITY_INTERRUPTIVE)
.setShowSystemUiTime(false)
.build());
...
}
</pre>
<p>The code snippet above configures peeking cards to be a single line tall, the background
of a peeking card to show only briefly and only for interruptive notifications, and the system
time not to be shown (since this watch face draws its own time representation).</p>
<p>You can configure the style of the system UI at any point in your watch face implementation.
For example, if the user selects a white background, you can add background protection for the
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>
<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 following code snippet shows how to obtain these properties:</p>
<pre>
&#64;Override
public void onPropertiesChanged(Bundle properties) {
super.onPropertiesChanged(properties);
mLowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
mBurnInProtection = properties.getBoolean(PROPERTY_BURN_IN_PROTECTION,
false);
}
</pre>
<p>You should take these device properties into account when drawing your watch face:</p>
<ul>
<li>For devices that use low-bit ambient mode, the screen supports fewer bits for each color
in ambient mode, so you should disable anti-aliasing.</li>
<li>For devices that require burn-in protection, avoid using large blocks of white pixels in
ambient mode and do not place content within 10 pixels of the edge of the screen, since the
system shifts the content periodically to avoid pixel burn-in.</li>
</ul>
<p>For more information about low-bit ambient mode and burn-in protection, see
<a href="{@docRoot}design/wear/watchfaces.html#SpecialScreens">Optimize for Special
Screens</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>
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>
<pre>
&#64;Override
public void onAmbientModeChanged(boolean inAmbientMode) {
boolean wasInAmbientMode = isInAmbientMode();
super.onAmbientModeChanged(inAmbientMode);
if (inAmbientMode != wasInAmbientMode) {
if (mLowBitAmbient) {
boolean antiAlias = !inAmbientMode;
mHourPaint.setAntiAlias(antiAlias);
mMinutePaint.setAntiAlias(antiAlias);
mSecondPaint.setAntiAlias(antiAlias);
mTickPaint.setAntiAlias(antiAlias);
}
invalidate();
updateTimer();
}
}
</pre>
<p>This example makes adjustments to some graphic styles and invalidates the canvas so the
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>
<ol>
<li>If this is the first invocation of the <code>onDraw()</code> 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>
<pre>
&#64;Override
public void onDraw(Canvas canvas, Rect bounds) {
// Update the time
mTime.setToNow();
int width = bounds.width();
int height = bounds.height();
// Draw the background, scaled to fit.
if (mBackgroundScaledBitmap == null
|| mBackgroundScaledBitmap.getWidth() != width
|| mBackgroundScaledBitmap.getHeight() != height) {
mBackgroundScaledBitmap = Bitmap.createScaledBitmap(mBackgroundBitmap,
width, height, true /* filter */);
}
canvas.drawBitmap(mBackgroundScaledBitmap, 0, 0, null);
// Find the center. Ignore the window insets so that, on round watches
// with a "chin", the watch face is centered on the entire screen, not
// just the usable portion.
float centerX = width / 2f;
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 secLength = centerX - 20;
float minLength = centerX - 40;
float hrLength = centerX - 80;
// Only draw the second hand in interactive mode.
if (!mAmbient) {
float secX = (float) Math.sin(secRot) * secLength;
float secY = (float) -Math.cos(secRot) * secLength;
canvas.drawLine(centerX, centerY, centerX + secX, centerY +
secY, mSecondPaint);
}
// Draw the minute and hour hands.
float minX = (float) Math.sin(minRot) * minLength;
float minY = (float) -Math.cos(minRot) * minLength;
canvas.drawLine(centerX, centerY, centerX + minX, centerY + minY,
mMinutePaint);
float hrX = (float) Math.sin(hrRot) * hrLength;
float hrY = (float) -Math.cos(hrRot) * hrLength;
canvas.drawLine(centerX, centerY, centerX + hrX, centerY + hrY,
mHourPaint);
}
</pre>
<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>
<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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -0,0 +1,62 @@
page.title=Creating Custom Watch Faces
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>Dependencies and Prerequisites</h2>
<ul>
<li>Android Studio 1.0.0 or later and Gradle 1.0 or later</li>
<li>Android 4.3 (API level 18) or higher on the handheld device</li>
<li>Android 5.0 (API level 21) or higher on the wearable device</li>
</ul>
</div>
</div>
<p>Watch faces in Android Wear leverage a dynamic digital canvas to tell time using colors,
animations, and relevant contextual information. The <a
href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app">Android
Wear companion app</a> provides watch faces with different styles and shapes. When
users select one of the available watch faces on the wearable or on the companion app, the
wearable device previews the watch face and lets the user set configuration options.</p>
<p>Android Wear enables you to create custom watch faces for Wear devices. When users install a
handheld app that contains a <a href="{@docRoot}training/wearables/apps/index.html">wearable
app</a> with watch faces, they become available in the Android Wear companion app
on the handheld device and in the watch face picker on the wearable device.</p>
<p>This class teaches you to implement custom watch faces and to package them inside a wearable
app. This class also covers design considerations and implementation tips to ensure that your
designs integrate with system UI elements and are power-efficient.</p>
<p class="note"><strong>Note:</strong> We recommend using <a
href="{@docRoot}sdk/index.html">Android Studio</a> for Android Wear development as
it provides project setup, library inclusion, and packaging conveniences that aren't available
in the Eclipse Android Developer Tools. This training assumes you are using Android Studio.</p>
<h2>Lessons</h2>
<dl>
<dt><a href="{@docRoot}training/wearables/watch-faces/designing.html">
Designing Watch Faces</a></dt>
<dd>Learn how to design a watch face that works on any Android Wear device.</dd>
<dt><a href="{@docRoot}training/wearables/watch-faces/service.html">
Building a Watch Face Service</a></dt>
<dd>Learn how to respond to important events during the lifecycle of your watch face.</dd>
<dt><a href="{@docRoot}training/wearables/watch-faces/drawing.html">
Drawing Watch Faces</a></dt>
<dd>Learn how to draw your watch face on a Wear device screen.</dd>
<dt><a href="{@docRoot}training/wearables/watch-faces/information.html">
Showing Information in Watch Faces</a></dt>
<dd>Learn how to incorporate contextual information into your watch face.</dd>
<dt><a href="{@docRoot}training/wearables/watch-faces/configuration.html">
Providing Configuration Activities</a></dt>
<dd>Learn how to create watch faces with configurable parameters.</dd>
<dt><a href="{@docRoot}training/wearables/watch-faces/issues.html">
Addressing Common Issues</a></dt>
<dd>Learn how to fix common problems when developing a watch face.</dd>
<dt><a href="{@docRoot}training/wearables/watch-faces/performance.html">
Optimizing Performance and Battery Life</a></dt>
<dd>Learn how to improve the frame rate of your animations and how to save power.</dd>
</dl>

View File

@@ -0,0 +1,213 @@
page.title=Showing Information in Watch Faces
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#Experience">Create a Compelling Experience</a></li>
<li><a href="#AddData">Add Data to Your Watch Face</a></li>
</ol>
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li>
</ul>
</div>
</div>
<p>In addition to telling time, Android Wear devices provide users with contextually relevant
information in the form of cards, notifications, and other wearable apps. Creating a custom
watch face not only gives you the opportunity to tell time in visually compelling ways, but
also to show users relevant information whenever they glance at their device.</p>
<p>Like any other wearable app, your watch face can communicate with apps running on the handheld
device using the <a href="{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer
API</a>. In some cases, you need to create an activity in the handheld app module of your project
that retrieves data from the Internet or from the user's profile and then shares it with your
watch face.</p>
<img src="{@docRoot}training/wearables/watch-faces/images/Render_Saturn.png"
width="200" height="196" alt="" style="margin-top:12px;margin-left:-20px"/>
<img src="{@docRoot}training/wearables/watch-faces/images/Render_Episode.png"
width="200" height="196" alt="" style="margin-top:12px;margin-left:-25px"/>
<p class="img-caption">
<strong>Figure 1.</strong> Examples of watch faces with integrated data.</p>
<h2 id="Experience">Create a Compelling Experience</h2>
<p>Before you design and implement a contextually-aware watch face, answer the following
questions:</p>
<ul>
<li>What kind of data do you want to incorporate?</li>
<li>Where can you obtain this data?</li>
<li>How often does the data change significantly?</li>
<li>How can you present the data such that users understand it at a glance?</li>
</ul>
<p>Android Wear devices are usually paired with a companion device that has a GPS sensor and
cellular connectivity, so you have endless possibilities to integrate different kinds of data
in your watch face, such as location, calendar events, social media trends, picture feeds, stock
market quotes, news events, sports scores, and so on. However, not all kinds of data are
appropriate for a watch face, so you should consider what kinds of data are most relevant to
your users throughout the day. Your watch face should also gracefully handle the case where the
wearable is not paired with a companion device or when an Internet connection is not available.</p>
<p>The active watch face on an Android Wear device is an app that runs continuously, so you
must retrieve data in a battery-efficient manner. For example, you can obtain the current
weather every ten minutes and store the results locally, instead of requesting an update every
minute. You can also refresh contextual data when the device switches from ambient to interactive
mode, since the user is more likely to glance at the watch when this transition occurs.</p>
<p>You should summarize contextual information on your watch face, since there is limited
space available on the screen and users just glance at their watch for a second or two at a
time. Sometimes the best way to convey contextual information is to react to it using graphics
and colors. For example, a watch face could change its background image depending on the current
weather.</p>
<h2 id="AddData">Add Data to Your Watch Face</h2>
<div style="float:right;margin-left:20px">
<img src="{@docRoot}training/wearables/watch-faces/images/preview_calendar.png"
width="180" height="180" alt="" style="margin-left:10px;margin-top:10px"/>
<p class="img-caption"><strong>Figure 2.</strong> The calendar watch face.</p>
</div>
<p>The <em>WatchFace</em> sample in the Android SDK demonstrates how to obtain calendar data
from the users profile in the <code>CalendarWatchFaceService</code> class and shows how many
meetings there are in the following twenty-four hours. This sample is located in the
<code>android-sdk/samples/android-21/wearable/WatchFace</code> directory.</p>
<p>To implement a watch face that incorporates contextual data, follow these steps:</p>
<ol>
<li>Provide a task that retrieves the data.</li>
<li>Create a custom timer to invoke your task periodically, or notify your watch face service
when external data changes.</li>
<li>Redraw your watch face with the updated data.</li>
</ol>
<p>The following sections describe these steps in detail.</p>
<h3 id="Task">Provide a task to retrieve data</h3>
<p>Create a class inside your <code>CanvasWatchFaceService.Engine</code> implementation that
extends {@link android.os.AsyncTask} and add the code to retrieve the data youre interested
in.</p>
<p>The <code>CalendarWatchFaceService</code> class obtains the number of meetings in the next
day as follows:</p>
<pre>
/* Asynchronous task to load the meetings from the content provider and
* report the number of meetings back using onMeetingsLoaded() */
private class LoadMeetingsTask extends AsyncTask&lt;Void, Void, Integer> {
&#64;Override
protected Integer doInBackground(Void... voids) {
long begin = System.currentTimeMillis();
Uri.Builder builder =
WearableCalendarContract.Instances.CONTENT_URI.buildUpon();
ContentUris.appendId(builder, begin);
ContentUris.appendId(builder, begin + DateUtils.DAY_IN_MILLIS);
final Cursor cursor = getContentResolver() .query(builder.build(),
null, null, null, null);
int numMeetings = cursor.getCount();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Num meetings: " + numMeetings);
}
return numMeetings;
}
&#64;Override
protected void onPostExecute(Integer result) {
/* get the number of meetings and set the next timer tick */
onMeetingsLoaded(result);
}
}
</pre>
<p>The <code>WearableCalendarContract</code> class from the Wearable Support Library provides
direct access to the user's calendar events from the companion device.</p>
<p>When the task finishes retrieving data, your code invokes a callback method. The following
sections describe how to implement the callback method in detail.</p>
<p>For more information about obtaining data from the calendar, see the <a
href="{@docRoot}guide/topics/providers/calendar-provider.html">Calendar Provider</a> API
guide.</p>
<h3 id="Timer">Create a custom timer</h3>
<p>You can implement a custom timer that ticks periodically to update your data.
The <code>CalendarWatchFaceService</code> class uses a {@link android.os.Handler} instance
that sends and processes delayed messages using the thread's message queue:</p>
<pre>
private class Engine extends CanvasWatchFaceService.Engine {
...
int mNumMeetings;
private AsyncTask&lt;Void, Void, Integer> mLoadMeetingsTask;
/* Handler to load the meetings once a minute in interactive mode. */
final Handler mLoadMeetingsHandler = new Handler() {
&#64;Override
public void handleMessage(Message message) {
switch (message.what) {
case MSG_LOAD_MEETINGS:
cancelLoadMeetingTask();
mLoadMeetingsTask = new LoadMeetingsTask();
mLoadMeetingsTask.execute();
break;
}
}
};
...
}
</pre>
<p>This method initializes the timer when the watch face becomes visible:</p>
<pre>
&#64;Override
public void onVisibilityChanged(boolean visible) {
super.onVisibilityChanged(visible);
if (visible) {
mLoadMeetingsHandler.sendEmptyMessage(MSG_LOAD_MEETINGS);
} else {
mLoadMeetingsHandler.removeMessages(MSG_LOAD_MEETINGS);
cancelLoadMeetingTask();
}
}
</pre>
<p>The next timer tick is set in the <code>onMeetingsLoaded()</code> method, as shown in the next
section.</p>
<h3 id="Redraw">Redraw your watch face with the updated data</h3>
<p>When the task that retrieves your data finishes, call the <code>invalidate()</code> method
so the system redraws your watch face. Store your data inside member variables of the
<code>Engine</code> class so you can access it inside the <code>onDraw()</code> method.</p>
<p>The <code>CalendarWatchFaceService</code> class provides a callback method for the task to
invoke when it finishes retrieving calendar data:</p>
<pre>
private void onMeetingsLoaded(Integer result) {
if (result != null) {
mNumMeetings = result;
invalidate();
}
if (isVisible()) {
mLoadMeetingsHandler.sendEmptyMessageDelayed(
MSG_LOAD_MEETINGS, LOAD_MEETINGS_DELAY_MS);
}
}
</pre>
<p>The callback method stores the result in a member variable, invalidates the view, and
schedules the next timer tick to run the task again.</p>

View File

@@ -0,0 +1,125 @@
page.title=Addressing Common Issues
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#ScreenShape">Detect the Shape of the Screen</a></li>
<li><a href="#PeekCards">Accomodate Peek Cards</a></li>
<li><a href="#RelativeMeasurements">Use Relative Measurements</a></li>
</ol>
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li>
</ul>
</div>
</div>
<p>Creating a custom watch face for Android Wear is substantially different from creating
notifications and wearable-specific activities. This class shows you how to resolve some
issues that you may encounter as you implement your first few watch faces.</p>
<h2 id="ScreenShape">Detect the Shape of the Screen</h2>
<p>Some Android Wear devices have square screens, while others have round screens. Devices with
round screens can contain an inset (or "chin") at the bottom of the screen. Your watch face
should adapt to and take advantage of the particular shape of the screen, as described in the
<a href="{@docRoot}design/wear/watchfaces.html">design guidelines</a>.</p>
<p>Android Wear lets your watch face determine the screen shape at runtime. To detect whether
the screen is square or round, override the <code>onApplyWindowInsets()</code> method in the
<code>CanvasWatchFaceService.Engine</code> class as follows:</p>
<pre>
private class Engine extends CanvasWatchFaceService.Engine {
boolean mIsRound;
int mChinSize;
&#64;Override
public void onApplyWindowInsets(WindowInsets insets) {
super.onApplyWindowInsets(insets);
mIsRound = insets.isRound();
mChinSize = insets.getSystemWindowInsetBottom();
}
...
}
</pre>
<p>To adapt your design when you draw your watch face, check the value of the
<code>mIsRound</code> and <code>mChinSize</code> member variables.</p>
<h2 id="PeekCards">Accomodate Peek Cards</h2>
<div style="float:right;margin-left:30px;width:340px">
<img src="{@docRoot}training/wearables/watch-faces/images/AnalogNoCard.png" alt=""
width="160" height="145" style="margin-right:7px"/>
<img src="{@docRoot}training/wearables/watch-faces/images/AnalogWithCard.png" alt=""
width="160" height="145"/>
<p class="img-caption"><strong>Figure 1.</strong> Some analog watch faces require adjustments
when notification cards appear.</p>
</div>
<p>When users receive a notification, the notification card may cover a significant portion of the
screen, depending on the
<a href="{@docRoot}training/wearables/watch-faces/drawing.html#SystemUI">system UI style</a>. Your
watch face should adapt to these situations by ensuring that users can still tell the time while
the notification card is present.</p>
<p>Analog watch faces can make adjustments when a notification card is present, like scaling
down the watch face to fit inside the portion of the screen not covered by the peek card. Digital
watch faces that display the time in the area of the screen not covered by peek cards do not
usually require adjustments. To determine the free space above the peek card so you can adapt
your watch face, use the <code>WatchFaceService.getPeekCardPosition()</code> method.</p>
<p>In ambient mode, peek cards have a transparent background. If your watch face contains details
near the card in ambient mode, consider drawing a black rectangle over them to ensure that users
can read the contents of the card.</p>
<h2 id="SystemIndicators">Configure the System Indicators</h2>
<div style="width:200px;float:right;margin-left:10px">
<img src="{@docRoot}training/wearables/watch-faces/images/Indicators_Cropped.png" alt=""
width="200" height="195"/>
<p class="img-caption" style="margin-left:25px;margin-top:-25px">
<strong>Figure 2.</strong> The status bar.</p>
</div>
<p>To ensure that the system indicators remain visible, you can configure their position on the
screen and whether they need background protection when you create a <code>WatchFaceStyle</code>
instance:</p>
<ul>
<li>To set the position of the status bar, use the <code>setStatusBarGravity()</code> method.</li>
<li>To set the position of the hotword, use the <code>setHotwordIndicatorGravity()</code>
method.</li>
<li>To protect the status bar and hotword with a semi-transparent gray background, use the
<code>setViewProtection()</code> method. This is usually necessary if your watch face has a
light background, since the system indicators are white.</li>
</ul>
<p>For more information about the system indicators, see <a
href="{@docRoot}training/wearables/watch-faces/drawing.html#SystemUI">Configure the System UI</a>
and read the <a href="{@docRoot}design/wear/watchfaces.html">design guidelines</a>.</p>
<h2 id="RelativeMeasurements">Use Relative Measurements</h2>
<p>Android Wear devices from different manufacturers feature screens with a variety of sizes and
resolutions. Your watch face should adapt to these variations by using relative measurements
instead of absolute pixel values.</p>
<p>When you draw your watch face, obtain the size of the canvas with the {@link
android.graphics.Canvas#getWidth Canvas.getWidth()} and {@link
android.graphics.Canvas#getHeight Canvas.getHeight()} methods and set the positions of your
graphic elements using values that are some fraction of the detected screen size. If you resize
the elements of your watch face in response to a peek card, use values that are some fraction
of the remaining space above the card to redraw your watch face.</p>

View File

@@ -0,0 +1,160 @@
page.title=Optimizing Performance and Battery Life
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#ReduceSize">Reduce the Size of Your Bitmap Assets</a></li>
<li><a href="#CombineBitmaps">Combine Bitmap Assets</a></li>
<li><a href="#AntiAlias">Disable Anti-Aliasing when Drawing Scaled Bitmaps</a></li>
<li><a href="#OutDrawing">Move Expensive Operations Outside the Drawing Method</a></li>
<li><a href="#SavePower">Follow Best Practices to Save Power</a></li>
</ol>
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li>
</ul>
</div>
</div>
<p>In addition to accommodating notification cards and system indicators, you need to ensure that
the animations in your watch face run smoothly and that your service does not perform unnecessary
computations. Watch faces in Android Wear run continuously on the device, so it is critical
that your watch face uses power efficiently.</p>
<p>This lesson provides some tips to speed up your animations and to measure and conserve
power on the device.</p>
<h2 id="ReduceSize">Reduce the Size of Your Bitmap Assets</h2>
<p>Many watch faces consist of a background image and other graphic assets that are transformed
and overlapped on top of the background image, such as clock hands and other elements of the design
that move over time. Typically these graphic elements are rotated (and sometimes scaled) inside the
<code>Engine.onDraw()</code> method every time the system redraws the watch face, as described in
<a href="{@docRoot}training/wearables/watch-faces/drawing.html#Drawing">Draw Your Watch
Face</a>.</p>
<p>The larger these graphic assets are, the more computationally expensive it is to transform them.
Transforming large graphic assets in the <code>Engine.onDraw()</code> method drastically reduces
the frame rate at which the system can run your animations.</p>
<div id="fig1" style="float:right;width:250px;margin-left:25px">
<img src="{@docRoot}training/wearables/watch-faces/images/ClockHandFull.png" alt=""
width="180" height="180"/>
<img src="{@docRoot}training/wearables/watch-faces/images/ClockHandCropped.png" alt=""
width="15" height="65" style="margin-left:25px"/>
<p class="img-caption">
<strong>Figure 1.</strong> Clock hands can be cropped to remove extra pixels.</p>
</div>
<p>To improve the performance of your watch face:</p>
<ul>
<li>Do not use graphic elements that are larger than you need.</li>
<li>Remove extra transparent pixels around the edges.</li>
</ul>
<p>The example clock hand on the left side of <a href="#fig1">Figure 1</a> can be reduced in size
by 97&#37;.</p>
<p>Reducing the size of your bitmap assets as described in this section not only improves
the performance of your animations, but it also saves power.</p>
<h2 id="CombineBitmaps">Combine Bitmap Assets</h2>
<p>If you have bitmaps that are often drawn together, consider combining them into the same
graphic asset. You can often combine the background image in interactive mode with the tick
marks to avoid drawing two full-screen bitmaps every time the system redraws the watch face.</p>
<h2 id="AntiAlias">Disable Anti-Aliasing when Drawing Scaled Bitmaps</h2>
<p>When you draw a scaled bitmap on the {@link android.graphics.Canvas} object using the {@link
android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint)
Canvas.drawBitmap()} method, you can provide a {@link android.graphics.Paint} instance to configure
several options. To improve performance, disable anti-aliasing using the {@link
android.graphics.Paint#setAntiAlias setAntiAlias()} method, since this option does not have any
effect on bitmaps.</p>
<div id="fig2" style="float:right;width:250px;margin-left:40px;margin-top:12px">
<img src="{@docRoot}training/wearables/watch-faces/images/BitmapFilterDisabled.png" alt=""
width="70" height="70" style="margin-left:20px"/>
<img src="{@docRoot}training/wearables/watch-faces/images/BitmapFilterEnabled.png" alt=""
width="70" height="70" style="margin-left:20px"/>
<p class="img-caption"><strong>Figure 2.</strong> Example of bitmap filtering disabled (left) and
enabled (right).</p>
</div>
<h3 id="BitmapFiltering">Use bitmap filtering</h3>
<p>For bitmap assets that you draw on top of other elements, enable bitmap filtering on the same
{@link android.graphics.Paint} instance using the {@link android.graphics.Paint#setFilterBitmap
setFilterBitmap()} method. <a href="#fig2">Figure 2</a> shows a magnified view of a clock hand with
and without bitmap filtering.</p>
<h2 id="OutDrawing">Move Expensive Operations Outside the Drawing Method</h2>
<p>The system calls the <code>Engine.onDraw()</code> method every time it redraws your watch
face, so you should only include operations that are strictly required to update the watch
face inside this method to improve performance.<p>
<p>When possible, avoid performing these operations inside the <code>onDraw()</code> method:</p>
<ul>
<li>Loading images and other resources.</li>
<li>Resizing images.</li>
<li>Allocating objects.</li>
<li>Performing computations whose result does not change between frames.</li>
</ul>
<p>You can usually perform these operations in the <code>Engine.onCreate()</code> method instead.
You can resize images ahead of time in the {@link
android.service.wallpaper.WallpaperService.Engine#onSurfaceChanged(android.view.SurfaceHolder, int, int, int)
Engine.onSurfaceChanged()} method, which provides you with the size of the canvas.</p>
<p>To analyze the performance of your watch face, use the Android Device Monitor. In particular,
ensure that the execution time for your <code>Engine.onDraw()</code> implementation is short and
consistent across invocations. For more information, see
<a href="{@docRoot}tools/debugging/ddms.html">Using DDMS</a>.</p>
<h2 id="SavePower">Follow Best Practices to Save Power</h2>
<p>In addition to the techniques described in the previous sections, follow the best
practices in this section to reduce the power consumption of your watch face.</p>
<h3>Reduce the frame rate of animations</h3>
<p>Animations are often computationally expensive and consume a significant amount of power. Most
animations look fluid at 30 frames per second, so you should avoid running your animations
at a higher frame rate.</p>
<h3>Let the CPU sleep</h3>
<p>Animations and small changes to the contents of the watch face wake up the CPU. Your watch
face should let the CPU sleep in between animations. For example, you can use short bursts of
animation every second in interactive mode and then let the CPU sleep until the next second.
Letting the CPU sleep often, even briefly, can significantly reduce power consumption.</p>
<p>To maximize battery life, use animations sparingly. Even a blinking colon wakes up the CPU with
every blink and hurts battery life.</p>
<h3>Monitor power consumption</h3>
<p>The <a href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app&hl=en">
Android Wear companion app</a> lets developers and users see how much battery different processes
on the wearable device are consuming under <strong>Settings</strong> > <strong>Watch
battery</strong>.</p>
<p>For more information about new features in Android 5.0 that help you improve battery life,
see <a href="{@docRoot}about/versions/android-5.0.html#Power">Project Volta</a>.</p>

View File

@@ -0,0 +1,280 @@
page.title=Building a Watch Face Service
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#CreateProject">Create and Configure Your Project</a></li>
<li><a href="#CallbackMethods">Implement the Service Callback Methods</a></li>
<li><a href="#RegisterService">Register the Service Implementation</a></li>
</ol>
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li>
</ul>
</div>
</div>
<p>Watch faces in Android Wear are implemented as <a
href="{@docRoot}guide/components/services.html">services</a> and packaged inside a <a
href="{@docRoot}training/wearables/apps/index.html">wearable app</a>. When users install a
handheld app that contains a wearable app with watch faces, these watch faces become available
in the <a
href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app&hl=en">Android
Wear companion app</a> on the handheld device and in the watch face picker on the wearable. When
users select one of the available watch faces, the wearable device shows the watch face and
invokes its service callback methods as required.</p>
<p>This lesson shows you how to configure an Android project to include watch faces and how
to implement the watch face service.</p>
<h2 id="CreateProject">Create and Configure Your Project</h2>
<p>To create an Android project for your watch face in Android Studio:</p>
<ol>
<li>Start Android Studio.</li>
<li>Create a new project:
<ul>
<li>If you don't have a project opened, in the <strong>Welcome</strong> screen, click
<strong>New Project</strong>.</li>
<li>If you have a project opened, from the <strong>File</strong> menu, select <strong>New
Project</strong>.</li>
</ul>
</li>
<li>Provide an application name and click <strong>Next</strong>.</li>
<li>Select the <strong>Phone and Tablet</strong> form factor.</li>
<li>Under <strong>Minimum SDK</strong>, choose API 18.</li>
<li>Select the <strong>Wear</strong> form factor.</li>
<li>Under <strong>Minimum SDK</strong>, choose API 21 and click <strong>Next</strong>.</li>
<li>Select <strong>Add No Activity</strong> and click <strong>Next</strong> in the two following
screens.</li>
<li>Click <strong>Finish</strong>.</li>
<li>Click <strong>View</strong> > <strong>Tool Windows</strong> > <strong>Project</strong> in the
IDE window.</li>
</ol>
<p>Android Studio creates a project with the <code>wear</code> and <code>mobile</code> modules.
For more information, see <a href="{@docRoot}sdk/installing/create-project.html">Creating a
Project</a>.</p>
<h3 id="Dependencies">Dependencies</h3>
<p>For the handheld app, edit the <code>build.gradle</code> file in the <code>mobile</code> module
to add these dependencies:</p>
<pre>
apply plugin: 'com.android.application'
android { ... }
dependencies {
...
wearApp project(':wear')
compile 'com.google.android.gms:play-services:6.1.+'
}
</pre>
<p>For the wearable app, edit the <code>build.gradle</code> file in the <code>wear</code> module
to add these dependencies:</p>
<pre>
apply plugin: 'com.android.application'
android { ... }
dependencies {
...
compile 'com.google.android.support:wearable:1.1.+'
compile 'com.google.android.gms:play-services-wearable:6.1.+'
}
</pre>
<p>The Wearable Support Library provides the necessary classes that you extend to create watch
face implementations. The Google Play services client libraries (<code>play-services</code> and
<code>play-services-wearable</code>) are required to sync data items between the companion device
and the wearable with the <a href="{@docRoot}training/wearables/data-layer/index.html">Wearable
Data Layer API</a>.</p>
<h3 id="Reference">Wearable Support Library API Reference</h3>
<p>The reference documentation provides detailed information about the classes you use to
implement watch faces. Download the
<a href="{@docRoot}shareables/training/wearable-support-docs.zip">API reference
documentation</a> for the Wearable Support Library.</p>
<h3 id="LibEclipse">Download the Wearable Support Library for Eclipse ADT</h3>
<p>If you are using the ADT plugin for Eclipse, download the
<a href="{@docRoot}shareables/training/wearable-support-lib.zip">Wearable Support Library</a> and
include it as a dependency in your project.</p>
<h3 id="Permissions">Declare Permissions</h3>
<p>Watch faces require the <code>PROVIDE_BACKGROUND</code> and <code>WAKE_LOCK</code> permissions.
Add the following permissions to the manifest files of both the wearable app and the mobile
app under the <code>manifest</code> element:</p>
<pre>
&lt;manifest ...>
&lt;uses-permission
android:name="com.google.android.permission.PROVIDE_BACKGROUND" />
&lt;uses-permission
android:name="android.permission.WAKE_LOCK" />
...
&lt;/manifest>
</pre>
<p class="caution"><strong>Caution:</strong> The handheld app must include all the permissions
declared in the wearable app.</p>
<h2 id="CallbackMethods">Implement the Service and Callback Methods</h2>
<p>Watch faces in Android Wear are implemented as
<a href="{@docRoot}guide/components/services.html">services</a>.
When a watch face is active, the system invokes the methods in its service when the time changes
or when an important event occurs (like switching to ambient mode or receiving a new
notification). The service implementation then draws the watch face on the screen using the
updated time and any other relevant data.</p>
<p>To implement a watch face, you extend the <code>CanvasWatchFaceService</code>
and <code>CanvasWatchFaceService.Engine</code> classes, and then you override the callback methods
in the <code>CanvasWatchFaceService.Engine</code> class. These classes are included in the
Wearable Support Library.</p>
<p>The following snippet outlines the key methods you need to implement:</p>
<pre>
public class AnalogWatchFaceService extends CanvasWatchFaceService {
&#64;Override
public Engine onCreateEngine() {
/* provide your watch face implementation */
return new Engine();
}
/* implement service callback methods */
private class Engine extends CanvasWatchFaceService.Engine {
&#64;Override
public void onCreate(SurfaceHolder holder) {
/* initialize your watch face */
}
&#64;Override
public void onPropertiesChanged(Bundle properties) {
/* get device features (burn-in, low-bit ambient) */
}
&#64;Override
public void onTimeTick() {
/* the time changed */
}
&#64;Override
public void onAmbientModeChanged(boolean inAmbientMode) {
/* the wearable switched between modes */
}
&#64;Override
public void onDraw(Canvas canvas) {
/* draw your watch face */
}
&#64;Override
public void onVisibilityChanged(boolean visible) {
/* the watch face became visible or invisible */
}
}
}
</pre>
<p class="note"><strong>Note:</strong> The <em>WatchFace</em> sample in the Android SDK
demonstrates how to implement analog and digital watch faces extending the
<code>CanvasWatchFaceService</code> class. This sample is located in the
<code>android-sdk/samples/android-21/wearable/WatchFace</code> directory.</p>
<p>The <code>CanvasWatchFaceService</code> class provides an invalidate mechanism similar to
the {@link android.view.View#invalidate View.invalidate()} method. You can call the
<code>invalidate()</code> method throughout your implementation when you want the system to
redraw the watch face. You can only use the <code>invalidate()</code> method in the main UI
thread. To invalidate the canvas from another thread, call the <code>postInvalidate()</code>
method.</p>
<p>For more information about implementing the methods in the
<code>CanvasWatchFaceService.Engine</code> class, see <a
href="{@docRoot}training/wearables/watch-faces/drawing.html">Drawing Watch Faces</a>.</p>
<h2 id="RegisterService">Register the Watch Face Service</h2>
<p>After you implement the watch face service, you register the implementation in the manifest
file of the wearable app. When users install this app, the system uses the information about
the service to make the watch face available in the <a
href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app&hl=en">Android
Wear companion app</a> and in the watch face picker on the wearable device.</p>
</p>The following snippet shows how to register a watch face implementation
under the <a href="{@docRoot}guide/topics/manifest/application-element.html">
<code>application</code></a> element:</p>
<pre>
&lt;service
android:name=".AnalogWatchFaceService"
android:label="&#64;string/analog_name"
android:allowEmbedded="true"
android:taskAffinity=""
android:permission="android.permission.BIND_WALLPAPER" >
&lt;meta-data
android:name="android.service.wallpaper"
android:resource="&#64;xml/watch_face" />
&lt;meta-data
android:name="com.google.android.wearable.watchface.preview"
android:resource="&#64;drawable/preview_analog" />
&lt;meta-data
android:name="com.google.android.wearable.watchface.preview_circular"
android:resource="&#64;drawable/preview_analog_circular" />
&lt;intent-filter>
&lt;action android:name="android.service.wallpaper.WallpaperService" />
&lt;category
android:name=
"com.google.android.wearable.watchface.category.WATCH_FACE" />
&lt;/intent-filter>
&lt;/service>
</pre>
<p>The <a
href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app&hl=en">Android
Wear companion app</a> and the watch face picker on the wearable device use the preview image
defined by the <code>com.google.android.wearable.watchface.preview</code> metadata entry when
presenting users with all the watch faces installed on the device. To obtain this drawable,
run the watch face on your Android Wear device or in an emulator instance and <a
href="{@docRoot}sdk/installing/studio-debug.html#screenCap">take a screenshot</a>. On Android Wear
devices with hdpi screens, the preview image is typically 320x320 pixels in size.</p>
<p>Watch faces that look substantially different on round devices can provide both round and
square preview images. To specify a round preview image, use the
<code>com.google.android.wearable.watchface.preview_circular</code> metadata entry. If a watch
face includes both preview images, the companion app and the watch face picker on the wearable
show the appropriate one, depending on the shape of the watch. If a round preview image is not
included, the square preview image is used for both square and round devices. For round devices,
a square preview image is cropped using a circular shape.</p>
<p>The <code>android.service.wallpaper</code> metadata entry specifies the
<code>watch_face.xml</code> resource file, which contains a <code>wallpaper</code>
element:</p>
<pre>
&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;wallpaper xmlns:android="http://schemas.android.com/apk/res/android" />
</pre>
<p>Your wearable app can contain more than one watch face. You must add a service entry to the
manifest file of the wearable app for each of your watch face implementations.</p>