Merge "docs: Creating Custom Watch Faces training class." into lmp-docs
@@ -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=
|
||||
|
||||
144
docs/html/training/wearables/watch-faces/configuration.jd
Normal 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>
|
||||
<service
|
||||
android:name=".DigitalWatchFaceService" ... />
|
||||
<!-- companion configuration activity -->
|
||||
<meta-data
|
||||
android:name=
|
||||
"com.google.android.wearable.watchface.companionConfigurationAction"
|
||||
android:value=
|
||||
"com.example.android.wearable.watchface.CONFIG_DIGITAL" />
|
||||
<!-- wearable configuration activity -->
|
||||
<meta-data
|
||||
android:name=
|
||||
"com.google.android.wearable.watchface.wearableConfigurationAction"
|
||||
android:value=
|
||||
"com.example.android.wearable.watchface.CONFIG_DIGITAL" />
|
||||
...
|
||||
</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>
|
||||
<activity
|
||||
android:name=".DigitalWatchFaceWearableConfigActivity"
|
||||
android:label="@string/digital_config_name">
|
||||
<intent-filter>
|
||||
<action android:name=
|
||||
"com.example.android.wearable.watchface.CONFIG_DIGITAL" />
|
||||
<category android:name=
|
||||
"com.google.android.wearable.watchface.category.WEARABLE_CONFIGURATION" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</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>
|
||||
108
docs/html/training/wearables/watch-faces/designing.jd
Normal 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>
|
||||
509
docs/html/training/wearables/watch-faces/drawing.jd
Normal 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() {
|
||||
@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() {
|
||||
@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>
|
||||
@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() && !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>
|
||||
@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>
|
||||
@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>
|
||||
@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>
|
||||
@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>
|
||||
@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>
|
||||
@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>
|
||||
BIN
docs/html/training/wearables/watch-faces/images/AnalogNoCard.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 44 KiB |
BIN
docs/html/training/wearables/watch-faces/images/Render_Next.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 50 KiB |
62
docs/html/training/wearables/watch-faces/index.jd
Normal 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>
|
||||
213
docs/html/training/wearables/watch-faces/information.jd
Normal 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 user’s 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 you’re 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<Void, Void, Integer> {
|
||||
@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;
|
||||
}
|
||||
|
||||
@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<Void, Void, Integer> mLoadMeetingsTask;
|
||||
|
||||
/* Handler to load the meetings once a minute in interactive mode. */
|
||||
final Handler mLoadMeetingsHandler = new Handler() {
|
||||
@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>
|
||||
@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>
|
||||
125
docs/html/training/wearables/watch-faces/issues.jd
Normal 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;
|
||||
|
||||
@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>
|
||||
160
docs/html/training/wearables/watch-faces/performance.jd
Normal 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%.</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>
|
||||
280
docs/html/training/wearables/watch-faces/service.jd
Normal 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>
|
||||
<manifest ...>
|
||||
<uses-permission
|
||||
android:name="com.google.android.permission.PROVIDE_BACKGROUND" />
|
||||
<uses-permission
|
||||
android:name="android.permission.WAKE_LOCK" />
|
||||
...
|
||||
</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 {
|
||||
|
||||
@Override
|
||||
public Engine onCreateEngine() {
|
||||
/* provide your watch face implementation */
|
||||
return new Engine();
|
||||
}
|
||||
|
||||
/* implement service callback methods */
|
||||
private class Engine extends CanvasWatchFaceService.Engine {
|
||||
|
||||
@Override
|
||||
public void onCreate(SurfaceHolder holder) {
|
||||
/* initialize your watch face */
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPropertiesChanged(Bundle properties) {
|
||||
/* get device features (burn-in, low-bit ambient) */
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeTick() {
|
||||
/* the time changed */
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAmbientModeChanged(boolean inAmbientMode) {
|
||||
/* the wearable switched between modes */
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas canvas) {
|
||||
/* draw your watch face */
|
||||
}
|
||||
|
||||
@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>
|
||||
<service
|
||||
android:name=".AnalogWatchFaceService"
|
||||
android:label="@string/analog_name"
|
||||
android:allowEmbedded="true"
|
||||
android:taskAffinity=""
|
||||
android:permission="android.permission.BIND_WALLPAPER" >
|
||||
<meta-data
|
||||
android:name="android.service.wallpaper"
|
||||
android:resource="@xml/watch_face" />
|
||||
<meta-data
|
||||
android:name="com.google.android.wearable.watchface.preview"
|
||||
android:resource="@drawable/preview_analog" />
|
||||
<meta-data
|
||||
android:name="com.google.android.wearable.watchface.preview_circular"
|
||||
android:resource="@drawable/preview_analog_circular" />
|
||||
<intent-filter>
|
||||
<action android:name="android.service.wallpaper.WallpaperService" />
|
||||
<category
|
||||
android:name=
|
||||
"com.google.android.wearable.watchface.category.WATCH_FACE" />
|
||||
</intent-filter>
|
||||
</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>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||