am 81556478: Sync sample prebuilts for mnc-dev

* commit '8155647801c9da4070bc0a044ec73afc126f4b88':
  Sync sample prebuilts for mnc-dev
diff --git a/samples/browseable/RuntimePermissions/src/com.example.android.common/logger/Log.java b/samples/browseable/RuntimePermissions/src/com.example.android.common.logger/Log.java
similarity index 100%
rename from samples/browseable/RuntimePermissions/src/com.example.android.common/logger/Log.java
rename to samples/browseable/RuntimePermissions/src/com.example.android.common.logger/Log.java
diff --git a/samples/browseable/RuntimePermissions/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/RuntimePermissions/src/com.example.android.common.logger/LogFragment.java
similarity index 100%
rename from samples/browseable/RuntimePermissions/src/com.example.android.common/logger/LogFragment.java
rename to samples/browseable/RuntimePermissions/src/com.example.android.common.logger/LogFragment.java
diff --git a/samples/browseable/RuntimePermissions/src/com.example.android.common/logger/LogNode.java b/samples/browseable/RuntimePermissions/src/com.example.android.common.logger/LogNode.java
similarity index 100%
rename from samples/browseable/RuntimePermissions/src/com.example.android.common/logger/LogNode.java
rename to samples/browseable/RuntimePermissions/src/com.example.android.common.logger/LogNode.java
diff --git a/samples/browseable/RuntimePermissions/src/com.example.android.common/logger/LogView.java b/samples/browseable/RuntimePermissions/src/com.example.android.common.logger/LogView.java
similarity index 100%
rename from samples/browseable/RuntimePermissions/src/com.example.android.common/logger/LogView.java
rename to samples/browseable/RuntimePermissions/src/com.example.android.common.logger/LogView.java
diff --git a/samples/browseable/RuntimePermissions/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/RuntimePermissions/src/com.example.android.common.logger/LogWrapper.java
similarity index 100%
rename from samples/browseable/RuntimePermissions/src/com.example.android.common/logger/LogWrapper.java
rename to samples/browseable/RuntimePermissions/src/com.example.android.common.logger/LogWrapper.java
diff --git a/samples/browseable/RuntimePermissions/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/RuntimePermissions/src/com.example.android.common.logger/MessageOnlyLogFilter.java
similarity index 100%
rename from samples/browseable/RuntimePermissions/src/com.example.android.common/logger/MessageOnlyLogFilter.java
rename to samples/browseable/RuntimePermissions/src/com.example.android.common.logger/MessageOnlyLogFilter.java
diff --git a/samples/browseable/RuntimePermissions/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/RuntimePermissions/src/com.example.android.common/activities/SampleActivityBase.java
deleted file mode 100644
index 3228927..0000000
--- a/samples/browseable/RuntimePermissions/src/com.example.android.common/activities/SampleActivityBase.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
-* Copyright 2013 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-package com.example.android.common.activities;
-
-import android.os.Bundle;
-import android.support.v4.app.FragmentActivity;
-
-import com.example.android.common.logger.Log;
-import com.example.android.common.logger.LogWrapper;
-
-/**
- * Base launcher activity, to handle most of the common plumbing for samples.
- */
-public class SampleActivityBase extends FragmentActivity {
-
-    public static final String TAG = "SampleActivityBase";
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-    }
-
-    @Override
-    protected  void onStart() {
-        super.onStart();
-        initializeLogging();
-    }
-
-    /** Set up targets to receive log data */
-    public void initializeLogging() {
-        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
-        // Wraps Android's native log framework
-        LogWrapper logWrapper = new LogWrapper();
-        Log.setLogNode(logWrapper);
-
-        Log.i(TAG, "Ready");
-    }
-}
diff --git a/samples/browseable/StorageProvider/_index.jd b/samples/browseable/StorageProvider/_index.jd
index 600fc61..ef6f646 100644
--- a/samples/browseable/StorageProvider/_index.jd
+++ b/samples/browseable/StorageProvider/_index.jd
@@ -1,5 +1,5 @@
 
-page.tags="MyCloud"
+page.tags="StorageProvider"
 sample.group=Content
 @jd:body
 
diff --git a/samples/browseable/StorageProvider/res/values/base-strings.xml b/samples/browseable/StorageProvider/res/values/base-strings.xml
index 1712bef..5fd804c 100644
--- a/samples/browseable/StorageProvider/res/values/base-strings.xml
+++ b/samples/browseable/StorageProvider/res/values/base-strings.xml
@@ -16,7 +16,7 @@
 -->
 
 <resources>
-    <string name="app_name">MyCloud</string>
+    <string name="app_name">StorageProvider</string>
     <string name="intro_message">
         <![CDATA[
         
diff --git a/samples/browseable/StorageProvider/src/com.example.android.storageprovider/MainActivity.java b/samples/browseable/StorageProvider/src/com.example.android.storageprovider/MainActivity.java
index 4d41ff4..5abfa12 100644
--- a/samples/browseable/StorageProvider/src/com.example.android.storageprovider/MainActivity.java
+++ b/samples/browseable/StorageProvider/src/com.example.android.storageprovider/MainActivity.java
@@ -36,7 +36,7 @@
 
     public static final String TAG = "MainActivity";
 
-    public static final String FRAGTAG = "MyCloudFragment";
+    public static final String FRAGTAG = "StorageProviderFragment";
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -45,7 +45,7 @@
 
         if (getSupportFragmentManager().findFragmentByTag(FRAGTAG) == null ) {
             FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
-            MyCloudFragment fragment = new MyCloudFragment();
+            StorageProviderFragment fragment = new StorageProviderFragment();
             transaction.add(fragment, FRAGTAG);
             transaction.commit();
         }
diff --git a/samples/browseable/WatchFace/Application/AndroidManifest.xml b/samples/browseable/WatchFace/Application/AndroidManifest.xml
index 732e306..5433c94 100644
--- a/samples/browseable/WatchFace/Application/AndroidManifest.xml
+++ b/samples/browseable/WatchFace/Application/AndroidManifest.xml
@@ -56,10 +56,10 @@
         </activity>
 
         <activity
-                android:name=".TiltWatchFaceConfigActivity"
+                android:name=".OpenGLWatchFaceConfigActivity"
                 android:label="@string/app_name">
             <intent-filter>
-                <action android:name="com.example.android.wearable.watchface.CONFIG_TILT" />
+                <action android:name="com.example.android.wearable.watchface.CONFIG_OPENGL" />
                 <category android:name="com.google.android.wearable.watchface.category.COMPANION_CONFIGURATION" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
diff --git a/samples/browseable/WatchFace/Application/res/layout/activity_tilt_watch_face_config.xml b/samples/browseable/WatchFace/Application/res/layout/activity_opengl_watch_face_config.xml
similarity index 95%
rename from samples/browseable/WatchFace/Application/res/layout/activity_tilt_watch_face_config.xml
rename to samples/browseable/WatchFace/Application/res/layout/activity_opengl_watch_face_config.xml
index bda2d68..f8c172d 100644
--- a/samples/browseable/WatchFace/Application/res/layout/activity_tilt_watch_face_config.xml
+++ b/samples/browseable/WatchFace/Application/res/layout/activity_opengl_watch_face_config.xml
@@ -20,7 +20,7 @@
 
     <TextView
         android:id="@+id/label"
-        android:text="@string/tilt_config_text"
+        android:text="@string/opengl_config_text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content" />
 
diff --git a/samples/browseable/WatchFace/Application/res/values/base-strings.xml b/samples/browseable/WatchFace/Application/res/values/base-strings.xml
index ef8f1d3..1b346c9 100644
--- a/samples/browseable/WatchFace/Application/res/values/base-strings.xml
+++ b/samples/browseable/WatchFace/Application/res/values/base-strings.xml
@@ -23,8 +23,8 @@
             
 This sample demonstrates how to create watch faces for android wear and includes a phone app
 and a wearable app. The wearable app has a variety of watch faces including analog, digital,
-opengl, calendar, etc. It also includes a watch-side configuration example. The phone app
-includes a phone-side configuration example.
+opengl, calendar, interactive, etc. It also includes a watch-side configuration example.
+The phone app includes a phone-side configuration example.
             
         
         ]]>
diff --git a/samples/browseable/WatchFace/Application/res/values/strings.xml b/samples/browseable/WatchFace/Application/res/values/strings.xml
index aacb108..6c6834f 100644
--- a/samples/browseable/WatchFace/Application/res/values/strings.xml
+++ b/samples/browseable/WatchFace/Application/res/values/strings.xml
@@ -16,7 +16,7 @@
 <resources>
     <string name="analog_config_text">This is the config activity for the Analog and Card Bounds watch faces</string>
     <string name="digital_config_text">Digital watch face configuration</string>
-    <string name="tilt_config_text">Tilt watch face configuration</string>
+    <string name="opengl_config_text">OpenGL watch face configuration</string>
     <string name="digital_config_background">Background</string>
     <string name="digital_config_hours">Hours</string>
     <string name="digital_config_minutes">Minutes</string>
diff --git a/samples/browseable/WatchFace/Application/src/com.example.android.wearable.watchface/TiltWatchFaceConfigActivity.java b/samples/browseable/WatchFace/Application/src/com.example.android.wearable.watchface/OpenGLWatchFaceConfigActivity.java
similarity index 74%
rename from samples/browseable/WatchFace/Application/src/com.example.android.wearable.watchface/TiltWatchFaceConfigActivity.java
rename to samples/browseable/WatchFace/Application/src/com.example.android.wearable.watchface/OpenGLWatchFaceConfigActivity.java
index 303e72e..49edd96 100644
--- a/samples/browseable/WatchFace/Application/src/com.example.android.wearable.watchface/TiltWatchFaceConfigActivity.java
+++ b/samples/browseable/WatchFace/Application/src/com.example.android.wearable.watchface/OpenGLWatchFaceConfigActivity.java
@@ -22,16 +22,21 @@
 import android.support.wearable.companion.WatchFaceCompanion;
 import android.widget.TextView;
 
-public class TiltWatchFaceConfigActivity extends Activity {
+/**
+ * The phone-side config activity for {@code OpenGLWatchFaceService}. The
+ * activity ({@code OpenGLWatchFaceWearableConfigActivity}) doesn't offer any configurations, but
+ * provides a template to add your own.
+ */
+public class OpenGLWatchFaceConfigActivity extends Activity {
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setContentView(R.layout.activity_tilt_watch_face_config);
+        setContentView(R.layout.activity_opengl_watch_face_config);
 
         ComponentName name =
                 getIntent().getParcelableExtra(WatchFaceCompanion.EXTRA_WATCH_FACE_COMPONENT);
-        TextView label = (TextView)findViewById(R.id.label);
+        TextView label = (TextView) findViewById(R.id.label);
         label.setText(label.getText() + " (" + name.getClassName() + ")");
     }
 }
diff --git a/samples/browseable/WatchFace/Wearable/AndroidManifest.xml b/samples/browseable/WatchFace/Wearable/AndroidManifest.xml
index 14fee36..c96d730 100644
--- a/samples/browseable/WatchFace/Wearable/AndroidManifest.xml
+++ b/samples/browseable/WatchFace/Wearable/AndroidManifest.xml
@@ -76,21 +76,21 @@
         </service>
 
         <service
-                android:name=".TiltWatchFaceService"
-                android:label="@string/tilt_name"
+                android:name=".OpenGLWatchFaceService"
+                android:label="@string/opengl_name"
                 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_tilt" />
+                    android:resource="@drawable/preview_opengl" />
             <meta-data
                     android:name="com.google.android.wearable.watchface.preview_circular"
-                    android:resource="@drawable/preview_tilt_circular" />
+                    android:resource="@drawable/preview_opengl_circular" />
             <meta-data
                     android:name="com.google.android.wearable.watchface.companionConfigurationAction"
-                    android:value="com.example.android.wearable.watchface.CONFIG_TILT" />
+                    android:value="com.example.android.wearable.watchface.CONFIG_OPENGL" />
 
             <intent-filter>
                 <action android:name="android.service.wallpaper.WallpaperService" />
@@ -120,6 +120,27 @@
             </intent-filter>
         </service>
 
+
+        <service
+                android:name=".InteractiveWatchFaceService"
+                android:label="@string/interactive_name"
+                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_interactive" />
+            <meta-data
+                android:name="com.google.android.wearable.watchface.preview_circular"
+                android:resource="@drawable/preview_interactive_circular" />
+            <intent-filter>
+                <action android:name="android.service.wallpaper.WallpaperService" />
+                <category
+                    android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
+            </intent-filter>
+        </service>
+
         <service
                 android:name=".DigitalWatchFaceService"
                 android:label="@string/digital_name"
diff --git a/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/bg.png b/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/bg.png
index 5199af2..c83911a 100644
--- a/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/bg.png
+++ b/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/bg.png
Binary files differ
diff --git a/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_analog.png b/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_analog.png
index ed6960d..af43c3d 100644
--- a/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_analog.png
+++ b/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_analog.png
Binary files differ
diff --git a/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_analog_circular.png b/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_analog_circular.png
index a3affe2..cb93b4e 100644
--- a/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_analog_circular.png
+++ b/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_analog_circular.png
Binary files differ
diff --git a/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_interactive.png b/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_interactive.png
new file mode 100644
index 0000000..cbfedd0
--- /dev/null
+++ b/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_interactive.png
Binary files differ
diff --git a/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_interactive_circular.png b/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_interactive_circular.png
new file mode 100644
index 0000000..9e51240
--- /dev/null
+++ b/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_interactive_circular.png
Binary files differ
diff --git a/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_tilt.png b/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_opengl.png
similarity index 100%
rename from samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_tilt.png
rename to samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_opengl.png
Binary files differ
diff --git a/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_tilt_circular.png b/samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_opengl_circular.png
similarity index 100%
rename from samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_tilt_circular.png
rename to samples/browseable/WatchFace/Wearable/res/drawable-hdpi/preview_opengl_circular.png
Binary files differ
diff --git a/samples/browseable/WatchFace/Wearable/res/values/dimens.xml b/samples/browseable/WatchFace/Wearable/res/values/dimens.xml
index aef847b..4973466 100644
--- a/samples/browseable/WatchFace/Wearable/res/values/dimens.xml
+++ b/samples/browseable/WatchFace/Wearable/res/values/dimens.xml
@@ -25,4 +25,11 @@
     <dimen name="digital_line_height">25dp</dimen>
     <dimen name="digital_config_color_picker_item_margin">32dp</dimen>
     <dimen name="content_padding_start">12dp</dimen>
+    <dimen name="interactive_text_size">20dp</dimen>
+    <dimen name="interactive_text_size_round">25dp</dimen>
+    <dimen name="interactive_x_offset">15dp</dimen>
+    <dimen name="interactive_x_offset_round">25dp</dimen>
+    <dimen name="interactive_y_offset">72dp</dimen>
+    <dimen name="interactive_y_offset_round">84dp</dimen>
+    <dimen name="interactive_line_height">25dp</dimen>
 </resources>
diff --git a/samples/browseable/WatchFace/Wearable/res/values/strings.xml b/samples/browseable/WatchFace/Wearable/res/values/strings.xml
index e54591f..19bc3e7 100644
--- a/samples/browseable/WatchFace/Wearable/res/values/strings.xml
+++ b/samples/browseable/WatchFace/Wearable/res/values/strings.xml
@@ -15,7 +15,8 @@
 -->
 <resources>
     <string name="app_name">WatchFace</string>
-    <string name="tilt_name">Sample Tilt</string>
+    <string name="opengl_name">Sample OpenGL</string>
+    <string name="interactive_name">Sample Interactive</string>
     <string name="analog_name">Sample Analog</string>
     <string name="sweep_name">Sample Sweep</string>
     <string name="card_bounds_name">Sample Card Bounds</string>
diff --git a/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/AnalogWatchFaceService.java b/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/AnalogWatchFaceService.java
index 16194b1..fb86ac7 100644
--- a/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/AnalogWatchFaceService.java
+++ b/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/AnalogWatchFaceService.java
@@ -20,16 +20,18 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Paint;
 import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.support.v7.graphics.Palette;
 import android.support.wearable.watchface.CanvasWatchFaceService;
 import android.support.wearable.watchface.WatchFaceService;
 import android.support.wearable.watchface.WatchFaceStyle;
@@ -50,7 +52,7 @@
 public class AnalogWatchFaceService extends CanvasWatchFaceService {
     private static final String TAG = "AnalogWatchFaceService";
 
-    /**
+    /*
      * Update rate in milliseconds for interactive mode. We update once a second to advance the
      * second hand.
      */
@@ -62,55 +64,73 @@
     }
 
     private class Engine extends CanvasWatchFaceService.Engine {
-        static final int MSG_UPDATE_TIME = 0;
+        private static final int MSG_UPDATE_TIME = 0;
 
-        static final float TWO_PI = (float) Math.PI * 2f;
+        private static final float HOUR_STROKE_WIDTH = 5f;
+        private static final float MINUTE_STROKE_WIDTH = 3f;
+        private static final float SECOND_TICK_STROKE_WIDTH = 2f;
 
-        Paint mHourPaint;
-        Paint mMinutePaint;
-        Paint mSecondPaint;
-        Paint mTickPaint;
-        boolean mMute;
-        Calendar mCalendar;
+        private static final float CENTER_GAP_AND_CIRCLE_RADIUS = 4f;
 
-        /** 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:
-                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                            Log.v(TAG, "updating 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;
-                }
-            }
-        };
+        private static final int SHADOW_RADIUS = 6;
 
-        final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
+        private Calendar mCalendar;
+        private boolean mRegisteredTimeZoneReceiver = false;
+        private boolean mMuteMode;
+
+        private float mCenterX;
+        private float mCenterY;
+
+        private float mSecondHandLength;
+        private float sMinuteHandLength;
+        private float sHourHandLength;
+
+        /* Colors for all hands (hour, minute, seconds, ticks) based on photo loaded. */
+        private int mWatchHandColor;
+        private int mWatchHandHightlightColor;
+        private int mWatchHandShadowColor;
+
+        private Paint mHourPaint;
+        private Paint mMinutePaint;
+        private Paint mSecondPaint;
+        private Paint mTickAndCirclePaint;
+
+        private Paint mBackgroundPaint;
+        private Bitmap mBackgroundBitmap;
+        private Bitmap mGrayBackgroundBitmap;
+
+        private boolean mAmbient;
+        private boolean mLowBitAmbient;
+        private boolean mBurnInProtection;
+
+        private Rect mPeekCardBounds = new Rect();
+
+        private final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
                 mCalendar.setTimeZone(TimeZone.getDefault());
                 invalidate();
             }
         };
-        boolean mRegisteredTimeZoneReceiver = false;
 
-        /**
-         * Whether the display supports fewer bits for each color in ambient mode. When true, we
-         * disable anti-aliasing in ambient mode.
-         */
-        boolean mLowBitAmbient;
+        /* Handler to update the time once a second in interactive mode. */
+        private final Handler mUpdateTimeHandler = new Handler() {
+            @Override
+            public void handleMessage(Message message) {
 
-        Bitmap mBackgroundBitmap;
-        Bitmap mBackgroundScaledBitmap;
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    Log.d(TAG, "updating 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);
+                }
+
+            }
+        };
 
         @Override
         public void onCreate(SurfaceHolder holder) {
@@ -125,32 +145,61 @@
                     .setShowSystemUiTime(false)
                     .build());
 
-            Resources resources = AnalogWatchFaceService.this.getResources();
-            Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg, null /* theme */);
-            mBackgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();
+            mBackgroundPaint = new Paint();
+            mBackgroundPaint.setColor(Color.BLACK);
+            mBackgroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg);
+
+            /* Set defaults for colors */
+            mWatchHandColor = Color.WHITE;
+            mWatchHandHightlightColor = Color.RED;
+            mWatchHandShadowColor = Color.BLACK;
 
             mHourPaint = new Paint();
-            mHourPaint.setARGB(255, 200, 200, 200);
-            mHourPaint.setStrokeWidth(5.f);
+            mHourPaint.setColor(mWatchHandColor);
+            mHourPaint.setStrokeWidth(HOUR_STROKE_WIDTH);
             mHourPaint.setAntiAlias(true);
             mHourPaint.setStrokeCap(Paint.Cap.ROUND);
+            mHourPaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
 
             mMinutePaint = new Paint();
-            mMinutePaint.setARGB(255, 200, 200, 200);
-            mMinutePaint.setStrokeWidth(3.f);
+            mMinutePaint.setColor(mWatchHandColor);
+            mMinutePaint.setStrokeWidth(MINUTE_STROKE_WIDTH);
             mMinutePaint.setAntiAlias(true);
             mMinutePaint.setStrokeCap(Paint.Cap.ROUND);
+            mMinutePaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
 
             mSecondPaint = new Paint();
-            mSecondPaint.setARGB(255, 255, 0, 0);
-            mSecondPaint.setStrokeWidth(2.f);
+            mSecondPaint.setColor(mWatchHandHightlightColor);
+            mSecondPaint.setStrokeWidth(SECOND_TICK_STROKE_WIDTH);
             mSecondPaint.setAntiAlias(true);
             mSecondPaint.setStrokeCap(Paint.Cap.ROUND);
+            mSecondPaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
 
-            mTickPaint = new Paint();
-            mTickPaint.setARGB(100, 255, 255, 255);
-            mTickPaint.setStrokeWidth(2.f);
-            mTickPaint.setAntiAlias(true);
+            mTickAndCirclePaint = new Paint();
+            mTickAndCirclePaint.setColor(mWatchHandColor);
+            mTickAndCirclePaint.setStrokeWidth(SECOND_TICK_STROKE_WIDTH);
+            mTickAndCirclePaint.setAntiAlias(true);
+            mTickAndCirclePaint.setStyle(Paint.Style.STROKE);
+            mTickAndCirclePaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
+
+            /* Extract colors from background image to improve watchface style. */
+            Palette.generateAsync(
+                    mBackgroundBitmap,
+                    new Palette.PaletteAsyncListener() {
+                        @Override
+                        public void onGenerated(Palette palette) {
+                            if (palette != null) {
+                                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                                    Log.d(TAG, "Palette: " + palette);
+                                }
+
+                                mWatchHandHightlightColor = palette.getVibrantColor(Color.RED);
+                                mWatchHandColor = palette.getLightVibrantColor(Color.WHITE);
+                                mWatchHandShadowColor = palette.getDarkMutedColor(Color.BLACK);
+                                updateWatchHandStyle();
+                            }
+                        }
+                    });
 
             mCalendar = Calendar.getInstance();
         }
@@ -164,18 +213,17 @@
         @Override
         public void onPropertiesChanged(Bundle properties) {
             super.onPropertiesChanged(properties);
-            mLowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
             if (Log.isLoggable(TAG, Log.DEBUG)) {
                 Log.d(TAG, "onPropertiesChanged: low-bit ambient = " + mLowBitAmbient);
             }
+
+            mLowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
+            mBurnInProtection = properties.getBoolean(PROPERTY_BURN_IN_PROTECTION, false);
         }
 
         @Override
         public void onTimeTick() {
             super.onTimeTick();
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "onTimeTick: ambient = " + isInAmbientMode());
-            }
             invalidate();
         }
 
@@ -185,26 +233,57 @@
             if (Log.isLoggable(TAG, Log.DEBUG)) {
                 Log.d(TAG, "onAmbientModeChanged: " + inAmbientMode);
             }
-            if (mLowBitAmbient) {
-                boolean antiAlias = !inAmbientMode;
-                mHourPaint.setAntiAlias(antiAlias);
-                mMinutePaint.setAntiAlias(antiAlias);
-                mSecondPaint.setAntiAlias(antiAlias);
-                mTickPaint.setAntiAlias(antiAlias);
-            }
-            invalidate();
+            mAmbient = inAmbientMode;
 
-            // Whether the timer should be running depends on whether we're in ambient mode (as well
-            // as whether we're visible), so we may need to start or stop the timer.
+            updateWatchHandStyle();
+
+            /* Check and trigger whether or not timer should be running (only in active mode). */
             updateTimer();
         }
 
+        private void updateWatchHandStyle(){
+            if (mAmbient){
+                mHourPaint.setColor(Color.WHITE);
+                mMinutePaint.setColor(Color.WHITE);
+                mSecondPaint.setColor(Color.WHITE);
+                mTickAndCirclePaint.setColor(Color.WHITE);
+
+                mHourPaint.setAntiAlias(false);
+                mMinutePaint.setAntiAlias(false);
+                mSecondPaint.setAntiAlias(false);
+                mTickAndCirclePaint.setAntiAlias(false);
+
+                mHourPaint.clearShadowLayer();
+                mMinutePaint.clearShadowLayer();
+                mSecondPaint.clearShadowLayer();
+                mTickAndCirclePaint.clearShadowLayer();
+
+            } else {
+                mHourPaint.setColor(mWatchHandColor);
+                mMinutePaint.setColor(mWatchHandColor);
+                mSecondPaint.setColor(mWatchHandHightlightColor);
+                mTickAndCirclePaint.setColor(mWatchHandColor);
+
+                mHourPaint.setAntiAlias(true);
+                mMinutePaint.setAntiAlias(true);
+                mSecondPaint.setAntiAlias(true);
+                mTickAndCirclePaint.setAntiAlias(true);
+
+                mHourPaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
+                mMinutePaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
+                mSecondPaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
+                mTickAndCirclePaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
+            }
+        }
+
         @Override
         public void onInterruptionFilterChanged(int interruptionFilter) {
             super.onInterruptionFilterChanged(interruptionFilter);
             boolean inMuteMode = (interruptionFilter == WatchFaceService.INTERRUPTION_FILTER_NONE);
-            if (mMute != inMuteMode) {
-                mMute = inMuteMode;
+
+            /* Dim display in mute mode. */
+            if (mMuteMode != inMuteMode) {
+                mMuteMode = inMuteMode;
                 mHourPaint.setAlpha(inMuteMode ? 100 : 255);
                 mMinutePaint.setAlpha(inMuteMode ? 100 : 255);
                 mSecondPaint.setAlpha(inMuteMode ? 80 : 255);
@@ -214,92 +293,179 @@
 
         @Override
         public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-            if (mBackgroundScaledBitmap == null
-                    || mBackgroundScaledBitmap.getWidth() != width
-                    || mBackgroundScaledBitmap.getHeight() != height) {
-                mBackgroundScaledBitmap = Bitmap.createScaledBitmap(mBackgroundBitmap,
-                        width, height, true /* filter */);
-            }
             super.onSurfaceChanged(holder, format, width, height);
+
+            /*
+             * Find the coordinates of the center point on the screen, and 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.
+             */
+            mCenterX = width / 2f;
+            mCenterY = height / 2f;
+
+            /*
+             * Calculate lengths of different hands based on watch screen size.
+             */
+            mSecondHandLength = (float) (mCenterX * 0.875);
+            sMinuteHandLength = (float) (mCenterX * 0.75);
+            sHourHandLength = (float) (mCenterX * 0.5);
+
+
+            /* Scale loaded background image (more efficient) if surface dimensions change. */
+            float scale = ((float) width) / (float) mBackgroundBitmap.getWidth();
+
+            mBackgroundBitmap = Bitmap.createScaledBitmap(mBackgroundBitmap,
+                    (int) (mBackgroundBitmap.getWidth() * scale),
+                    (int) (mBackgroundBitmap.getHeight() * scale), true);
+
+            /*
+             * Create a gray version of the image only if it will look nice on the device in
+             * ambient mode. That means we don't want devices that support burn-in
+             * protection (slight movements in pixels, not great for images going all the way to
+             * edges) and low ambient mode (degrades image quality).
+             *
+             * Also, if your watch face will know about all images ahead of time (users aren't
+             * selecting their own photos for the watch face), it will be more
+             * efficient to create a black/white version (png, etc.) and load that when you need it.
+             */
+            if (!mBurnInProtection && !mLowBitAmbient) {
+                initGrayBackgroundBitmap();
+            }
+        }
+
+        private void initGrayBackgroundBitmap() {
+            mGrayBackgroundBitmap = Bitmap.createBitmap(
+                    mBackgroundBitmap.getWidth(),
+                    mBackgroundBitmap.getHeight(),
+                    Bitmap.Config.ARGB_8888);
+            Canvas canvas = new Canvas(mGrayBackgroundBitmap);
+            Paint grayPaint = new Paint();
+            ColorMatrix colorMatrix = new ColorMatrix();
+            colorMatrix.setSaturation(0);
+            ColorMatrixColorFilter filter = new ColorMatrixColorFilter(colorMatrix);
+            grayPaint.setColorFilter(filter);
+            canvas.drawBitmap(mBackgroundBitmap, 0, 0, grayPaint);
         }
 
         @Override
         public void onDraw(Canvas canvas, Rect bounds) {
-            mCalendar.setTimeInMillis(System.currentTimeMillis());
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "onDraw");
+            }
+            long now = System.currentTimeMillis();
+            mCalendar.setTimeInMillis(now);
 
-            int width = bounds.width();
-            int height = bounds.height();
+            if (mAmbient && (mLowBitAmbient || mBurnInProtection)) {
+                canvas.drawColor(Color.BLACK);
+            } else if (mAmbient) {
+                canvas.drawBitmap(mGrayBackgroundBitmap, 0, 0, mBackgroundPaint);
+            } else {
+                canvas.drawBitmap(mBackgroundBitmap, 0, 0, mBackgroundPaint);
+            }
 
-            // Draw the background, scaled to fit.
-            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;
-
-            // Draw the ticks.
-            float innerTickRadius = centerX - 10;
-            float outerTickRadius = centerX;
+            /*
+             * Draw ticks. Usually you will want to bake this directly into the photo, but in
+             * cases where you want to allow users to select their own photos, this dynamically
+             * creates them on top of the photo.
+             */
+            float innerTickRadius = mCenterX - 10;
+            float outerTickRadius = mCenterX;
             for (int tickIndex = 0; tickIndex < 12; tickIndex++) {
-                float tickRot = tickIndex * TWO_PI / 12;
+                float tickRot = (float) (tickIndex * Math.PI * 2 / 12);
                 float innerX = (float) Math.sin(tickRot) * innerTickRadius;
                 float innerY = (float) -Math.cos(tickRot) * innerTickRadius;
                 float outerX = (float) Math.sin(tickRot) * outerTickRadius;
                 float outerY = (float) -Math.cos(tickRot) * outerTickRadius;
-                canvas.drawLine(centerX + innerX, centerY + innerY,
-                        centerX + outerX, centerY + outerY, mTickPaint);
+                canvas.drawLine(mCenterX + innerX, mCenterY + innerY,
+                        mCenterX + outerX, mCenterY + outerY, mTickAndCirclePaint);
             }
 
-            float seconds =
-                    mCalendar.get(Calendar.SECOND) + mCalendar.get(Calendar.MILLISECOND) / 1000f;
-            float secRot = seconds / 60f * TWO_PI;
-            float minutes = mCalendar.get(Calendar.MINUTE) + seconds / 60f;
-            float minRot = minutes / 60f * TWO_PI;
-            float hours = mCalendar.get(Calendar.HOUR) + minutes / 60f;
-            float hrRot = hours / 12f * TWO_PI;
+            /*
+             * These calculations reflect the rotation in degrees per unit of time, e.g.,
+             * 360 / 60 = 6 and 360 / 12 = 30.
+             */
+            final float seconds =
+                    (mCalendar.get(Calendar.SECOND) + mCalendar.get(Calendar.MILLISECOND) / 1000f);
+            final float secondsRotation = seconds * 6f;
 
-            float secLength = centerX - 20;
-            float minLength = centerX - 40;
-            float hrLength = centerX - 80;
+            final float minutesRotation = mCalendar.get(Calendar.MINUTE) * 6f;
 
-            if (!isInAmbientMode()) {
-                float secX = (float) Math.sin(secRot) * secLength;
-                float secY = (float) -Math.cos(secRot) * secLength;
-                canvas.drawLine(centerX, centerY, centerX + secX, centerY + secY, mSecondPaint);
+            final float hourHandOffset = mCalendar.get(Calendar.MINUTE) / 2f;
+            final float hoursRotation = (mCalendar.get(Calendar.HOUR) * 30) + hourHandOffset;
+
+            /*
+             * Save the canvas state before we can begin to rotate it.
+             */
+            canvas.save();
+
+            canvas.rotate(hoursRotation, mCenterX, mCenterY);
+            canvas.drawLine(
+                    mCenterX,
+                    mCenterY - CENTER_GAP_AND_CIRCLE_RADIUS,
+                    mCenterX,
+                    mCenterY - sHourHandLength,
+                    mHourPaint);
+
+            canvas.rotate(minutesRotation - hoursRotation, mCenterX, mCenterY);
+            canvas.drawLine(
+                    mCenterX,
+                    mCenterY - CENTER_GAP_AND_CIRCLE_RADIUS,
+                    mCenterX,
+                    mCenterY - sMinuteHandLength,
+                    mMinutePaint);
+
+            /*
+             * Ensure the "seconds" hand is drawn only when we are in interactive mode.
+             * Otherwise, we only update the watch face once a minute.
+             */
+            if (!mAmbient) {
+                canvas.rotate(secondsRotation - minutesRotation, mCenterX, mCenterY);
+                canvas.drawLine(
+                        mCenterX,
+                        mCenterY - CENTER_GAP_AND_CIRCLE_RADIUS,
+                        mCenterX,
+                        mCenterY - mSecondHandLength,
+                        mSecondPaint);
+
             }
+            canvas.drawCircle(
+                    mCenterX,
+                    mCenterY,
+                    CENTER_GAP_AND_CIRCLE_RADIUS,
+                    mTickAndCirclePaint);
 
-            float minX = (float) Math.sin(minRot) * minLength;
-            float minY = (float) -Math.cos(minRot) * minLength;
-            canvas.drawLine(centerX, centerY, centerX + minX, centerY + minY, mMinutePaint);
+            /* Restore the canvas' original orientation. */
+            canvas.restore();
 
-            float hrX = (float) Math.sin(hrRot) * hrLength;
-            float hrY = (float) -Math.cos(hrRot) * hrLength;
-            canvas.drawLine(centerX, centerY, centerX + hrX, centerY + hrY, mHourPaint);
+            /* Draw rectangle behind peek card in ambient mode to improve readability. */
+            if (mAmbient) {
+                canvas.drawRect(mPeekCardBounds, mBackgroundPaint);
+            }
         }
 
         @Override
         public void onVisibilityChanged(boolean visible) {
             super.onVisibilityChanged(visible);
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "onVisibilityChanged: " + visible);
-            }
 
             if (visible) {
                 registerReceiver();
-
-                // Update time zone in case it changed while we weren't visible.
+                /* Update time zone in case it changed while we weren't visible. */
                 mCalendar.setTimeZone(TimeZone.getDefault());
+                invalidate();
             } else {
                 unregisterReceiver();
             }
 
-            // Whether the timer should be running depends on whether we're visible (as well as
-            // whether we're in ambient mode), so we may need to start or stop the timer.
+            /* Check and trigger whether or not timer should be running (only in active mode). */
             updateTimer();
         }
 
+        @Override
+        public void onPeekCardPositionUpdate(Rect rect) {
+            super.onPeekCardPositionUpdate(rect);
+            mPeekCardBounds.set(rect);
+        }
+
         private void registerReceiver() {
             if (mRegisteredTimeZoneReceiver) {
                 return;
@@ -318,8 +484,7 @@
         }
 
         /**
-         * Starts the {@link #mUpdateTimeHandler} timer if it should be running and isn't currently
-         * or stops it if it shouldn't be running but currently is.
+         * Starts/stops the {@link #mUpdateTimeHandler} timer based on the state of the watch face.
          */
         private void updateTimer() {
             if (Log.isLoggable(TAG, Log.DEBUG)) {
@@ -332,12 +497,11 @@
         }
 
         /**
-         * Returns whether the {@link #mUpdateTimeHandler} timer should be running. The timer should
-         * only run when we're visible and in interactive mode.
+         * Returns whether the {@link #mUpdateTimeHandler} timer should be running. The timer
+         * should only run in active mode.
          */
         private boolean shouldTimerBeRunning() {
-            return isVisible() && !isInAmbientMode();
+            return isVisible() && !mAmbient;
         }
-
     }
 }
diff --git a/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/InteractiveWatchFaceService.java b/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/InteractiveWatchFaceService.java
new file mode 100644
index 0000000..1a6f25b
--- /dev/null
+++ b/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/InteractiveWatchFaceService.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.wearable.watchface;
+
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.wearable.watchface.CanvasWatchFaceService;
+import android.support.wearable.watchface.WatchFaceStyle;
+import android.util.Log;
+import android.view.SurfaceHolder;
+import android.view.WindowInsets;
+
+/**
+ * Demostrates interactive watch face capabilities, i.e., touching the display and registering
+ * three different events: touch, touch-cancel and tap. The watch face UI will show the count of
+ * these events as they occur. See the {@code onTapCommand} below.
+ */
+public class InteractiveWatchFaceService extends CanvasWatchFaceService {
+
+    private static final String TAG = "InteractiveWatchFace";
+
+    private static final Typeface BOLD_TYPEFACE =
+            Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD);
+    private static final Typeface NORMAL_TYPEFACE =
+            Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL);
+
+    @Override
+    public Engine onCreateEngine() {
+        return new Engine();
+    }
+
+    private class Engine extends CanvasWatchFaceService.Engine {
+
+        private Paint mTextPaint;
+        private final Paint mPeekCardBackgroundPaint = new Paint();
+
+        private float mXOffset;
+        private float mYOffset;
+        private float mTextSpacingHeight;
+        private int mScreenTextColor = Color.WHITE;
+
+        private int mTouchCommandTotal;
+        private int mTouchCancelCommandTotal;
+        private int mTapCommandTotal;
+
+        private int mTouchCoordinateX;
+        private int mTouchCoordinateY;
+
+        private final Rect mCardBounds = new Rect();
+
+        /**
+         * Whether the display supports fewer bits for each color in ambient mode. When true, we
+         * disable anti-aliasing in ambient mode.
+         */
+        private boolean mLowBitAmbient;
+
+        @Override
+        public void onCreate(SurfaceHolder holder) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onCreate");
+            }
+            super.onCreate(holder);
+
+            /** Accepts tap events via WatchFaceStyle (setAcceptsTapEvents(true)). */
+            setWatchFaceStyle(new WatchFaceStyle.Builder(InteractiveWatchFaceService.this)
+                    .setCardPeekMode(WatchFaceStyle.PEEK_MODE_VARIABLE)
+                    .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
+                    .setShowSystemUiTime(false)
+                    .setAcceptsTapEvents(true)
+                    .build());
+
+            Resources resources = InteractiveWatchFaceService.this.getResources();
+            mTextSpacingHeight = resources.getDimension(R.dimen.interactive_text_size);
+
+            mTextPaint = new Paint();
+            mTextPaint.setColor(mScreenTextColor);
+            mTextPaint.setTypeface(BOLD_TYPEFACE);
+            mTextPaint.setAntiAlias(true);
+
+            mTouchCommandTotal = 0;
+            mTouchCancelCommandTotal = 0;
+            mTapCommandTotal = 0;
+
+            mTouchCoordinateX = 0;
+            mTouchCoordinateX = 0;
+        }
+
+        @Override
+        public void onApplyWindowInsets(WindowInsets insets) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onApplyWindowInsets: " + (insets.isRound() ? "round" : "square"));
+            }
+            super.onApplyWindowInsets(insets);
+
+            /** Loads offsets / text size based on device type (square vs. round). */
+            Resources resources = InteractiveWatchFaceService.this.getResources();
+            boolean isRound = insets.isRound();
+            mXOffset = resources.getDimension(
+                    isRound ? R.dimen.interactive_x_offset_round : R.dimen.interactive_x_offset);
+            mYOffset = resources.getDimension(
+                    isRound ? R.dimen.interactive_y_offset_round : R.dimen.interactive_y_offset);
+
+            float textSize = resources.getDimension(
+                    isRound ? R.dimen.interactive_text_size_round : R.dimen.interactive_text_size);
+
+            mTextPaint.setTextSize(textSize);
+        }
+
+        @Override
+        public void onPeekCardPositionUpdate(Rect bounds) {
+            super.onPeekCardPositionUpdate(bounds);
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onPeekCardPositionUpdate: " + bounds);
+            }
+            super.onPeekCardPositionUpdate(bounds);
+            if (!bounds.equals(mCardBounds)) {
+                mCardBounds.set(bounds);
+                invalidate();
+            }
+        }
+
+        @Override
+        public void onPropertiesChanged(Bundle properties) {
+            super.onPropertiesChanged(properties);
+
+            boolean burnInProtection = properties.getBoolean(PROPERTY_BURN_IN_PROTECTION, false);
+            mTextPaint.setTypeface(burnInProtection ? NORMAL_TYPEFACE : BOLD_TYPEFACE);
+
+            mLowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
+
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onPropertiesChanged: burn-in protection = " + burnInProtection
+                        + ", low-bit ambient = " + mLowBitAmbient);
+            }
+        }
+
+        @Override
+        public void onAmbientModeChanged(boolean inAmbientMode) {
+            super.onAmbientModeChanged(inAmbientMode);
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onAmbientModeChanged: " + inAmbientMode);
+            }
+
+            if (mLowBitAmbient) {
+                boolean antiAlias = !inAmbientMode;
+                mTextPaint.setAntiAlias(antiAlias);
+            }
+            invalidate();
+        }
+
+        /*
+         * Captures tap event (and tap type) and increments correct tap type total.
+         */
+        @Override
+        public void onTapCommand(int tapType, int x, int y, long eventTime) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Tap Command: " + tapType);
+            }
+
+            mTouchCoordinateX = x;
+            mTouchCoordinateY = y;
+
+            switch(tapType) {
+                case TAP_TYPE_TOUCH:
+                    mTouchCommandTotal++;
+                    break;
+                case TAP_TYPE_TOUCH_CANCEL:
+                    mTouchCancelCommandTotal++;
+                    break;
+                case TAP_TYPE_TAP:
+                    mTapCommandTotal++;
+                    break;
+            }
+
+            invalidate();
+        }
+
+        @Override
+        public void onDraw(Canvas canvas, Rect bounds) {
+            /** Draws background */
+            canvas.drawColor(Color.BLACK);
+
+            canvas.drawText(
+                    "TAP: " + String.valueOf(mTapCommandTotal),
+                    mXOffset,
+                    mYOffset,
+                    mTextPaint);
+
+            canvas.drawText(
+                    "CANCEL: " + String.valueOf(mTouchCancelCommandTotal),
+                    mXOffset,
+                    mYOffset + mTextSpacingHeight,
+                    mTextPaint);
+
+            canvas.drawText(
+                    "TOUCH: " + String.valueOf(mTouchCommandTotal),
+                    mXOffset,
+                    mYOffset + (mTextSpacingHeight * 2),
+                    mTextPaint);
+
+            canvas.drawText(
+                    "X, Y: " + mTouchCoordinateX + ", " + mTouchCoordinateY,
+                    mXOffset,
+                    mYOffset + (mTextSpacingHeight * 3),
+                    mTextPaint
+            );
+
+            /** Covers area under peek card */
+            if (isInAmbientMode()) {
+                canvas.drawRect(mCardBounds, mPeekCardBackgroundPaint);
+            }
+        }
+    }
+}
diff --git a/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/TiltWatchFaceService.java b/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/OpenGLWatchFaceService.java
similarity index 97%
rename from samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/TiltWatchFaceService.java
rename to samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/OpenGLWatchFaceService.java
index 879473c..01adcdb 100644
--- a/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/TiltWatchFaceService.java
+++ b/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/OpenGLWatchFaceService.java
@@ -37,9 +37,9 @@
  * {@link Gles2ColoredTriangleList}s. The camera moves around in interactive mode and stops moving
  * when the watch enters ambient mode.
  */
-public class TiltWatchFaceService extends Gles2WatchFaceService {
+public class OpenGLWatchFaceService extends Gles2WatchFaceService {
 
-    private static final String TAG = "TiltWatchFaceService";
+    private static final String TAG = "OpenGLWatchFaceService";
 
     /** Expected frame rate in interactive mode. */
     private static final long FPS = 60;
@@ -129,7 +129,7 @@
                 Log.d(TAG, "onCreate");
             }
             super.onCreate(surfaceHolder);
-            setWatchFaceStyle(new WatchFaceStyle.Builder(TiltWatchFaceService.this)
+            setWatchFaceStyle(new WatchFaceStyle.Builder(OpenGLWatchFaceService.this)
                     .setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
                     .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
                     .setStatusBarGravity(Gravity.RIGHT | Gravity.TOP)
@@ -395,7 +395,7 @@
             }
             mRegisteredTimeZoneReceiver = true;
             IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
-            TiltWatchFaceService.this.registerReceiver(mTimeZoneReceiver, filter);
+            OpenGLWatchFaceService.this.registerReceiver(mTimeZoneReceiver, filter);
         }
 
         private void unregisterReceiver() {
@@ -403,7 +403,7 @@
                 return;
             }
             mRegisteredTimeZoneReceiver = false;
-            TiltWatchFaceService.this.unregisterReceiver(mTimeZoneReceiver);
+            OpenGLWatchFaceService.this.unregisterReceiver(mTimeZoneReceiver);
         }
 
         @Override
diff --git a/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/SweepWatchFaceService.java b/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/SweepWatchFaceService.java
index d547f1c..0ba2ab9 100644
--- a/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/SweepWatchFaceService.java
+++ b/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/SweepWatchFaceService.java
@@ -20,14 +20,16 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Paint;
 import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+import android.support.v7.graphics.Palette;
 import android.support.wearable.watchface.CanvasWatchFaceService;
 import android.support.wearable.watchface.WatchFaceService;
 import android.support.wearable.watchface.WatchFaceStyle;
@@ -45,6 +47,7 @@
  * {@link AnalogWatchFaceService} is similar but has a ticking second hand.
  */
 public class SweepWatchFaceService extends CanvasWatchFaceService {
+
     private static final String TAG = "SweepWatchFaceService";
 
     @Override
@@ -53,32 +56,53 @@
     }
 
     private class Engine extends CanvasWatchFaceService.Engine {
-        static final float TWO_PI = (float) Math.PI * 2f;
 
-        Paint mHourPaint;
-        Paint mMinutePaint;
-        Paint mSecondPaint;
-        Paint mTickPaint;
-        boolean mMute;
-        Calendar mCalendar;
+        private static final float HOUR_STROKE_WIDTH = 5f;
+        private static final float MINUTE_STROKE_WIDTH = 3f;
+        private static final float SECOND_TICK_STROKE_WIDTH = 2f;
 
-        final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
+        private static final float CENTER_GAP_AND_CIRCLE_RADIUS = 4f;
+
+        private static final int SHADOW_RADIUS = 6;
+
+        private Calendar mCalendar;
+        private boolean mRegisteredTimeZoneReceiver = false;
+        private boolean mMuteMode;
+
+        private float mCenterX;
+        private float mCenterY;
+
+        private float mSecondHandLength;
+        private float mMinuteHandLength;
+        private float mHourHandLength;
+
+        /* Colors for all hands (hour, minute, seconds, ticks) based on photo loaded. */
+        private int mWatchHandColor;
+        private int mWatchHandHightlightColor;
+        private int mWatchHandShadowColor;
+
+        private Paint mHourPaint;
+        private Paint mMinutePaint;
+        private Paint mSecondPaint;
+        private Paint mTickAndCirclePaint;
+
+        private Paint mBackgroundPaint;
+        private Bitmap mBackgroundBitmap;
+        private Bitmap mGrayBackgroundBitmap;
+
+        private boolean mAmbient;
+        private boolean mLowBitAmbient;
+        private boolean mBurnInProtection;
+
+        private Rect mPeekCardBounds = new Rect();
+
+        private final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
                 mCalendar.setTimeZone(TimeZone.getDefault());
                 invalidate();
             }
         };
-        boolean mRegisteredTimeZoneReceiver = false;
-
-        /**
-         * Whether the display supports fewer bits for each color in ambient mode. When true, we
-         * disable anti-aliasing in ambient mode.
-         */
-        boolean mLowBitAmbient;
-
-        Bitmap mBackgroundBitmap;
-        Bitmap mBackgroundScaledBitmap;
 
         @Override
         public void onCreate(SurfaceHolder holder) {
@@ -93,32 +117,61 @@
                     .setShowSystemUiTime(false)
                     .build());
 
-            Resources resources = SweepWatchFaceService.this.getResources();
-            Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg, null /* theme */);
-            mBackgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();
+            mBackgroundPaint = new Paint();
+            mBackgroundPaint.setColor(Color.BLACK);
+            mBackgroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg);
+
+            /* Set defaults for colors */
+            mWatchHandColor = Color.WHITE;
+            mWatchHandHightlightColor = Color.RED;
+            mWatchHandShadowColor = Color.BLACK;
 
             mHourPaint = new Paint();
-            mHourPaint.setARGB(255, 200, 200, 200);
-            mHourPaint.setStrokeWidth(5.f);
+            mHourPaint.setColor(mWatchHandColor);
+            mHourPaint.setStrokeWidth(HOUR_STROKE_WIDTH);
             mHourPaint.setAntiAlias(true);
             mHourPaint.setStrokeCap(Paint.Cap.ROUND);
+            mHourPaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
 
             mMinutePaint = new Paint();
-            mMinutePaint.setARGB(255, 200, 200, 200);
-            mMinutePaint.setStrokeWidth(3.f);
+            mMinutePaint.setColor(mWatchHandColor);
+            mMinutePaint.setStrokeWidth(MINUTE_STROKE_WIDTH);
             mMinutePaint.setAntiAlias(true);
             mMinutePaint.setStrokeCap(Paint.Cap.ROUND);
+            mMinutePaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
 
             mSecondPaint = new Paint();
-            mSecondPaint.setARGB(255, 255, 0, 0);
-            mSecondPaint.setStrokeWidth(2.f);
+            mSecondPaint.setColor(mWatchHandHightlightColor);
+            mSecondPaint.setStrokeWidth(SECOND_TICK_STROKE_WIDTH);
             mSecondPaint.setAntiAlias(true);
             mSecondPaint.setStrokeCap(Paint.Cap.ROUND);
+            mSecondPaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
 
-            mTickPaint = new Paint();
-            mTickPaint.setARGB(100, 255, 255, 255);
-            mTickPaint.setStrokeWidth(2.f);
-            mTickPaint.setAntiAlias(true);
+            mTickAndCirclePaint = new Paint();
+            mTickAndCirclePaint.setColor(mWatchHandColor);
+            mTickAndCirclePaint.setStrokeWidth(SECOND_TICK_STROKE_WIDTH);
+            mTickAndCirclePaint.setAntiAlias(true);
+            mTickAndCirclePaint.setStyle(Paint.Style.STROKE);
+            mTickAndCirclePaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
+
+            /* Extract colors from background image to improve watchface style. */
+            Palette.generateAsync(
+                    mBackgroundBitmap,
+                    new Palette.PaletteAsyncListener() {
+                        @Override
+                        public void onGenerated(Palette palette) {
+                            if (palette != null) {
+                                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                                    Log.d(TAG, "Palette: " + palette);
+                                }
+
+                                mWatchHandHightlightColor = palette.getVibrantColor(Color.RED);
+                                mWatchHandColor = palette.getLightVibrantColor(Color.WHITE);
+                                mWatchHandShadowColor = palette.getDarkMutedColor(Color.BLACK);
+                                updateWatchHandStyle();
+                            }
+                        }
+                    });
 
             mCalendar = Calendar.getInstance();
         }
@@ -126,18 +179,17 @@
         @Override
         public void onPropertiesChanged(Bundle properties) {
             super.onPropertiesChanged(properties);
-            mLowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
             if (Log.isLoggable(TAG, Log.DEBUG)) {
                 Log.d(TAG, "onPropertiesChanged: low-bit ambient = " + mLowBitAmbient);
             }
+
+            mLowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
+            mBurnInProtection = properties.getBoolean(PROPERTY_BURN_IN_PROTECTION, false);
         }
 
         @Override
         public void onTimeTick() {
             super.onTimeTick();
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "onTimeTick: ambient = " + isInAmbientMode());
-            }
             invalidate();
         }
 
@@ -147,22 +199,56 @@
             if (Log.isLoggable(TAG, Log.DEBUG)) {
                 Log.d(TAG, "onAmbientModeChanged: " + inAmbientMode);
             }
-            if (mLowBitAmbient) {
-                boolean antiAlias = !inAmbientMode;
-                mHourPaint.setAntiAlias(antiAlias);
-                mMinutePaint.setAntiAlias(antiAlias);
-                mSecondPaint.setAntiAlias(antiAlias);
-                mTickPaint.setAntiAlias(antiAlias);
-            }
+            mAmbient = inAmbientMode;
+
+            updateWatchHandStyle();
+
             invalidate();
         }
 
+        private void updateWatchHandStyle(){
+            if (mAmbient){
+                mHourPaint.setColor(Color.WHITE);
+                mMinutePaint.setColor(Color.WHITE);
+                mSecondPaint.setColor(Color.WHITE);
+                mTickAndCirclePaint.setColor(Color.WHITE);
+
+                mHourPaint.setAntiAlias(false);
+                mMinutePaint.setAntiAlias(false);
+                mSecondPaint.setAntiAlias(false);
+                mTickAndCirclePaint.setAntiAlias(false);
+
+                mHourPaint.clearShadowLayer();
+                mMinutePaint.clearShadowLayer();
+                mSecondPaint.clearShadowLayer();
+                mTickAndCirclePaint.clearShadowLayer();
+
+            } else {
+                mHourPaint.setColor(mWatchHandColor);
+                mMinutePaint.setColor(mWatchHandColor);
+                mSecondPaint.setColor(mWatchHandHightlightColor);
+                mTickAndCirclePaint.setColor(mWatchHandColor);
+
+                mHourPaint.setAntiAlias(true);
+                mMinutePaint.setAntiAlias(true);
+                mSecondPaint.setAntiAlias(true);
+                mTickAndCirclePaint.setAntiAlias(true);
+
+                mHourPaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
+                mMinutePaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
+                mSecondPaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
+                mTickAndCirclePaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
+            }
+        }
+
         @Override
         public void onInterruptionFilterChanged(int interruptionFilter) {
             super.onInterruptionFilterChanged(interruptionFilter);
             boolean inMuteMode = (interruptionFilter == WatchFaceService.INTERRUPTION_FILTER_NONE);
-            if (mMute != inMuteMode) {
-                mMute = inMuteMode;
+
+            /* Dim display in mute mode. */
+            if (mMuteMode != inMuteMode) {
+                mMuteMode = inMuteMode;
                 mHourPaint.setAlpha(inMuteMode ? 100 : 255);
                 mMinutePaint.setAlpha(inMuteMode ? 100 : 255);
                 mSecondPaint.setAlpha(inMuteMode ? 80 : 255);
@@ -172,13 +258,58 @@
 
         @Override
         public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-            if (mBackgroundScaledBitmap == null
-                    || mBackgroundScaledBitmap.getWidth() != width
-                    || mBackgroundScaledBitmap.getHeight() != height) {
-                mBackgroundScaledBitmap = Bitmap.createScaledBitmap(mBackgroundBitmap,
-                        width, height, true /* filter */);
-            }
             super.onSurfaceChanged(holder, format, width, height);
+
+            /*
+             * Find the coordinates of the center point on the screen, and 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.
+             */
+            mCenterX = width / 2f;
+            mCenterY = height / 2f;
+
+            /*
+             * Calculate lengths of different hands based on watch screen size.
+             */
+            mSecondHandLength = (float) (mCenterX * 0.875);
+            mMinuteHandLength = (float) (mCenterX * 0.75);
+            mHourHandLength = (float) (mCenterX * 0.5);
+
+
+            /* Scale loaded background image (more efficient) if surface dimensions change. */
+            float scale = ((float) width) / (float) mBackgroundBitmap.getWidth();
+
+            mBackgroundBitmap = Bitmap.createScaledBitmap(mBackgroundBitmap,
+                    (int) (mBackgroundBitmap.getWidth() * scale),
+                    (int) (mBackgroundBitmap.getHeight() * scale), true);
+
+            /*
+             * Create a gray version of the image only if it will look nice on the device in
+             * ambient mode. That means we don't want devices that support burn-in
+             * protection (slight movements in pixels, not great for images going all the way to
+             * edges) and low ambient mode (degrades image quality).
+             *
+             * Also, if your watch face will know about all images ahead of time (users aren't
+             * selecting their own photos for the watch face), it will be more
+             * efficient to create a black/white version (png, etc.) and load that when you need it.
+             */
+            if (!mBurnInProtection && !mLowBitAmbient) {
+                initGrayBackgroundBitmap();
+            }
+        }
+
+        private void initGrayBackgroundBitmap() {
+            mGrayBackgroundBitmap = Bitmap.createBitmap(
+                    mBackgroundBitmap.getWidth(),
+                    mBackgroundBitmap.getHeight(),
+                    Bitmap.Config.ARGB_8888);
+            Canvas canvas = new Canvas(mGrayBackgroundBitmap);
+            Paint grayPaint = new Paint();
+            ColorMatrix colorMatrix = new ColorMatrix();
+            colorMatrix.setSaturation(0);
+            ColorMatrixColorFilter filter = new ColorMatrixColorFilter(colorMatrix);
+            grayPaint.setColorFilter(filter);
+            canvas.drawBitmap(mBackgroundBitmap, 0, 0, grayPaint);
         }
 
         @Override
@@ -189,59 +320,95 @@
             long now = System.currentTimeMillis();
             mCalendar.setTimeInMillis(now);
 
-            int width = bounds.width();
-            int height = bounds.height();
+            if (mAmbient && (mLowBitAmbient || mBurnInProtection)) {
+                canvas.drawColor(Color.BLACK);
+            } else if (mAmbient) {
+                canvas.drawBitmap(mGrayBackgroundBitmap, 0, 0, mBackgroundPaint);
+            } else {
+                canvas.drawBitmap(mBackgroundBitmap, 0, 0, mBackgroundPaint);
+            }
 
-            // Draw the background, scaled to fit.
-            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;
-
-            // Draw the ticks.
-            float innerTickRadius = centerX - 10;
-            float outerTickRadius = centerX;
+            /*
+             * Draw ticks. Usually you will want to bake this directly into the photo, but in
+             * cases where you want to allow users to select their own photos, this dynamically
+             * creates them on top of the photo.
+             */
+            float innerTickRadius = mCenterX - 10;
+            float outerTickRadius = mCenterX;
             for (int tickIndex = 0; tickIndex < 12; tickIndex++) {
                 float tickRot = (float) (tickIndex * Math.PI * 2 / 12);
                 float innerX = (float) Math.sin(tickRot) * innerTickRadius;
                 float innerY = (float) -Math.cos(tickRot) * innerTickRadius;
                 float outerX = (float) Math.sin(tickRot) * outerTickRadius;
                 float outerY = (float) -Math.cos(tickRot) * outerTickRadius;
-                canvas.drawLine(centerX + innerX, centerY + innerY,
-                        centerX + outerX, centerY + outerY, mTickPaint);
+                canvas.drawLine(mCenterX + innerX, mCenterY + innerY,
+                        mCenterX + outerX, mCenterY + outerY, mTickAndCirclePaint);
             }
 
-            float seconds =
-                    mCalendar.get(Calendar.SECOND) + mCalendar.get(Calendar.MILLISECOND) / 1000f;
-            float secRot = seconds / 60f * TWO_PI;
-            float minutes = mCalendar.get(Calendar.MINUTE) + seconds / 60f;
-            float minRot = minutes / 60f * TWO_PI;
-            float hours = mCalendar.get(Calendar.HOUR) + minutes / 60f;
-            float hrRot = hours / 12f * TWO_PI;
+            /*
+             * These calculations reflect the rotation in degrees per unit of time, e.g.,
+             * 360 / 60 = 6 and 360 / 12 = 30.
+             */
+            final float seconds =
+                    (mCalendar.get(Calendar.SECOND) + mCalendar.get(Calendar.MILLISECOND) / 1000f);
+            final float secondsRotation = seconds * 6f;
 
-            float secLength = centerX - 20;
-            float minLength = centerX - 40;
-            float hrLength = centerX - 80;
+            final float minutesRotation = mCalendar.get(Calendar.MINUTE) * 6f;
 
-            if (!isInAmbientMode()) {
-                float secX = (float) Math.sin(secRot) * secLength;
-                float secY = (float) -Math.cos(secRot) * secLength;
-                canvas.drawLine(centerX, centerY, centerX + secX, centerY + secY, mSecondPaint);
+            final float hourHandOffset = mCalendar.get(Calendar.MINUTE) / 2f;
+            final float hoursRotation = (mCalendar.get(Calendar.HOUR) * 30) + hourHandOffset;
+
+            /*
+             * Save the canvas state before we can begin to rotate it.
+             */
+            canvas.save();
+
+            canvas.rotate(hoursRotation, mCenterX, mCenterY);
+            canvas.drawLine(
+                    mCenterX,
+                    mCenterY - CENTER_GAP_AND_CIRCLE_RADIUS,
+                    mCenterX,
+                    mCenterY - mHourHandLength,
+                    mHourPaint);
+
+            canvas.rotate(minutesRotation - hoursRotation, mCenterX, mCenterY);
+            canvas.drawLine(
+                    mCenterX,
+                    mCenterY - CENTER_GAP_AND_CIRCLE_RADIUS,
+                    mCenterX,
+                    mCenterY - mMinuteHandLength,
+                    mMinutePaint);
+
+            /*
+             * Ensure the "seconds" hand is drawn only when we are in interactive mode.
+             * Otherwise, we only update the watch face once a minute.
+             */
+            if (!mAmbient) {
+                canvas.rotate(secondsRotation - minutesRotation, mCenterX, mCenterY);
+                canvas.drawLine(
+                        mCenterX,
+                        mCenterY - CENTER_GAP_AND_CIRCLE_RADIUS,
+                        mCenterX,
+                        mCenterY - mSecondHandLength,
+                        mSecondPaint);
+
+            }
+            canvas.drawCircle(
+                    mCenterX,
+                    mCenterY,
+                    CENTER_GAP_AND_CIRCLE_RADIUS,
+                    mTickAndCirclePaint);
+
+            /* Restore the canvas' original orientation. */
+            canvas.restore();
+
+            /* Draw rectangle behind peek card in ambient mode to improve readability. */
+            if (mAmbient) {
+                canvas.drawRect(mPeekCardBounds, mBackgroundPaint);
             }
 
-            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);
-
-            // Draw every frame as long as we're visible and in interactive mode.
-            if (isVisible() && !isInAmbientMode()) {
+            /* Draw every frame as long as we're visible and in interactive mode. */
+            if ((isVisible()) && (!mAmbient)) {
                 invalidate();
             }
         }
@@ -252,16 +419,20 @@
 
             if (visible) {
                 registerReceiver();
-
-                // Update time zone in case it changed while we weren't visible.
+                /* Update time zone in case it changed while we weren't visible. */
                 mCalendar.setTimeZone(TimeZone.getDefault());
-
                 invalidate();
             } else {
                 unregisterReceiver();
             }
         }
 
+        @Override
+        public void onPeekCardPositionUpdate(Rect rect) {
+            super.onPeekCardPositionUpdate(rect);
+            mPeekCardBounds.set(rect);
+        }
+
         private void registerReceiver() {
             if (mRegisteredTimeZoneReceiver) {
                 return;
diff --git a/samples/browseable/WatchFace/_index.jd b/samples/browseable/WatchFace/_index.jd
index 8c803fa..8b779d0 100644
--- a/samples/browseable/WatchFace/_index.jd
+++ b/samples/browseable/WatchFace/_index.jd
@@ -7,7 +7,7 @@
             
 This sample demonstrates how to create watch faces for android wear and includes a phone app
 and a wearable app. The wearable app has a variety of watch faces including analog, digital,
-opengl, calendar, etc. It also includes a watch-side configuration example. The phone app
-includes a phone-side configuration example.
+opengl, calendar, interactive, etc. It also includes a watch-side configuration example.
+The phone app includes a phone-side configuration example.
             
         </p>