Merge "Updates metadata for "ActionBarCompat-Basic" sample" into lmp-docs
diff --git a/admin/AppRestrictionSchema/screenshots/main.png b/admin/AppRestrictionSchema/screenshots/main.png
new file mode 100644
index 0000000..0d0d9c4
--- /dev/null
+++ b/admin/AppRestrictionSchema/screenshots/main.png
Binary files differ
diff --git a/admin/AppRestrictionSchema/template-params.xml b/admin/AppRestrictionSchema/template-params.xml
index c6ec4a1..6603034 100644
--- a/admin/AppRestrictionSchema/template-params.xml
+++ b/admin/AppRestrictionSchema/template-params.xml
@@ -39,4 +39,72 @@
     <common src="logger" />
     <common src="activities" />
 
+    <metadata>
+        <status>PUBLISHED</status>
+        <categories>Device Admin</categories>
+        <technologies>Android</technologies>
+        <languages>Java</languages>
+        <solutions>Mobile</solutions>
+        <level>ADVANCED</level>
+        <icon>Application/main/big_icon.png</icon>
+        <screenshots>
+            <img>screenshots/main.png</img>
+        </screenshots>
+        <api_refs>
+            <android>android.content.RestrictionsManager</android>
+        </api_refs>
+
+        <description>
+A basic app showing how to allow a device administrator to restrict user
+activities using the Android Device Administration API. The app exports
+a custom policy that enables or disables a UI control. Device Administration
+applications are able to enforce a specific value for this policy, as
+directed by enterprise administrators.
+        </description>
+
+        <intro>
+<![CDATA[
+The [Android Device Administration API][1] allows enterprise administrators to
+enforce specific policies on a managed device. The system provides policies
+that control settings such as password complexity, screen lock, or camera
+availability. Developers can also augment this list with custom policies
+that control specific features within their applications. For example,
+a web browser could provide access to a whitelist of allowed domains.
+
+The list of policies exposed by an app must be specified using a file
+inside of the `res/xml` directory, using the `<restriction>` tag:
+
+```xml
+<restrictions xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <restriction
+            android:defaultValue="false"
+            android:description="@string/description_can_say_hello"
+            android:key="can_say_hello"
+            android:restrictionType="bool"
+            android:title="@string/title_can_say_hello" />
+
+</restrictions>
+```
+
+In this sample, that file can be found at
+`Application/src/main/res/xml/app_restrictions.xml`. This file must be
+also be declared inside of `ApplicationManifest.xml` using a `<meta-data>`
+element:
+
+```xml
+<meta-data
+        android:name="android.content.APP_RESTRICTIONS"
+        android:resource="@xml/app_restrictions" />
+```
+
+At runtime, the current list of restrictions enforced by policy can be
+checked by calling [RestrictionsManager.getApplicationRestrictions()][2].
+
+[1]: http://developer.android.com/guide/topics/admin/device-admin.html
+[2]: https://developer.android.com/reference/android/content/RestrictionsManager.html#getApplicationRestrictions()
+]]>
+        </intro>
+    </metadata>
+
 </sample>
diff --git a/build.gradle b/build.gradle
index 740e531..789ffce 100644
--- a/build.gradle
+++ b/build.gradle
@@ -90,7 +90,8 @@
 "wearable/wear/SpeedTracker",
 "wearable/wear/SynchronizedNotifications",
 "wearable/wear/Timer",
-"wearable/wear/WatchViewStub"
+"wearable/wear/WatchViewStub",
+"wearable/wear/WatchFace",
 ]
 
 List<String> taskNames = [
diff --git a/media/MediaBrowserService/README.md b/media/MediaBrowserService/README.md
index b61692e..bda9824 100644
--- a/media/MediaBrowserService/README.md
+++ b/media/MediaBrowserService/README.md
@@ -53,7 +53,7 @@
        android:resource="@xml/automotive_app_desc"/>
 ```
 
-  And in res/values/automotive\_app\_desc.xml:
+  And in res/xml/automotive\_app\_desc.xml:
 ```
       <?xml version="1.0" encoding="utf-8"?>
       <automotiveApp>
@@ -61,7 +61,7 @@
       </automotiveApp>
 ```
 
-- declare and export the service in AndroidManifest:
+- declare and export the service in AndroidManifest.xml:
 ```
     <service
         android:name=".service.MusicService"
@@ -84,12 +84,6 @@
 This sample uses the Gradle build system. To build this project, use the
 "gradlew build" command or use "Import Project" in Android Studio.
 
-Screenshots
------------
-
-<!-- Update these to point to screenshots. Add more as needed. -->
-![Description](screenshots/image1.png) ![Description](screenshots/image2.png)
-
 Support
 -------
 
diff --git a/notification/MessagingService/README.md b/notification/MessagingService/README.md
index 4cb5bb8..69e3aa3 100644
--- a/notification/MessagingService/README.md
+++ b/notification/MessagingService/README.md
@@ -6,19 +6,23 @@
 the notification with a CarExtender to make it compatible with Android Auto.
 Each unread conversation from a user is sent as a distinct notification.
 
-CheckList while building a messaging app that supports Android Auto:
+Checklist while building a messaging app that supports Android Auto:
 -------------------------------------------------------------------
-1. Add or import the android-auto-sdk.jar into your app.
-2. Ensure that Message notifications are extended using
+1. Ensure that Message notifications are extended using
 NotificationCompat.Builder.extend(new CarExtender()...)
-3. Add meta-data to your AndroidManifest.xml to specify that your app
+2. Declare a meta-data tag to your AndroidManifest.xml to specify that your app
 is automotive enabled.
+
+example: AndroidManifest.xml
+
 ```
        <meta-data android:name="com.google.android.gms.car.application"
                    android:resource="@xml/automotive_app_desc"/>
 ```
-and include the following to indicate that the application wants to show notifications on
+
+Include the following to indicate that the application wants to show notifications on
 the Android Auto overview screen.
+
 res/xml/automotive\_app\_desc.xml
 ```
 <automotiveApp>
@@ -29,8 +33,8 @@
 Flow
 -----
 MessagingFragment is shown to the user. Depending on the button clicked, the MessagingService is
-sent a message. MessagingService inturn creates notifications which can be viewed either on the
-emulator or in a car.
+sent a message. MessagingService in turn creates notifications which can be viewed either on the
+device or in the messaging-simulator.
 When a message is read, the associated PendingIntent is called and MessageReadReceiver is called
 with the appropriate conversationId. Similarly, when a reply is received, the MessageReplyReceiver
 is called with the appropriate conversationId. MessageLogger logs each event and shows them in a
@@ -49,12 +53,6 @@
 This sample uses the Gradle build system. To build this project, use the
 "gradlew build" command or use "Import Project" in Android Studio.
 
-Screenshots
------------
-
-<!-- Update these to point to screenshots. Add more as needed. -->
-![Description](screenshots/image1.png) ![Description](screenshots/image2.png)
-
 Support
 -------
 
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/screenshots/1-main.png b/ui/activityscenetransition/ActivitySceneTransitionBasic/screenshots/1-main.png
new file mode 100644
index 0000000..539e3e4
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/screenshots/1-main.png
Binary files differ
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/screenshots/2-transition.png b/ui/activityscenetransition/ActivitySceneTransitionBasic/screenshots/2-transition.png
new file mode 100644
index 0000000..96d27d0
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/screenshots/2-transition.png
Binary files differ
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/screenshots/3-transition.png b/ui/activityscenetransition/ActivitySceneTransitionBasic/screenshots/3-transition.png
new file mode 100644
index 0000000..08e8f54
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/screenshots/3-transition.png
Binary files differ
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/screenshots/4-detail.png b/ui/activityscenetransition/ActivitySceneTransitionBasic/screenshots/4-detail.png
new file mode 100644
index 0000000..91d65be
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/screenshots/4-detail.png
Binary files differ
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/screenshots/icon-web.png b/ui/activityscenetransition/ActivitySceneTransitionBasic/screenshots/icon-web.png
new file mode 100644
index 0000000..715c319
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/screenshots/icon-web.png
Binary files differ
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/template-params.xml b/ui/activityscenetransition/ActivitySceneTransitionBasic/template-params.xml
index ae954d4..35da366 100644
--- a/ui/activityscenetransition/ActivitySceneTransitionBasic/template-params.xml
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/template-params.xml
@@ -41,4 +41,37 @@
     <template src="base"/>
     <common src="logger"/>
 
+    <metadata>
+        <status>PUBLISHED</status>
+        <categories>UI</categories>
+        <technologies>Android</technologies>
+        <languages>Java</languages>
+        <solutions>Mobile</solutions>
+        <level>INTERMEDIATE</level>
+        <icon>screenshots/icon-web.png</icon>
+        <screenshots>
+            <img>screenshots/1-main.png</img>
+            <img>screenshots/2-transition.png</img>
+            <img>screenshots/3-transition.png</img>
+            <img>screenshots/4-detail.png</img>
+        </screenshots>
+        <api_refs>
+            <android>android.transition.Transition</android>
+            <android>android.app.ActivityOptions</android>
+        </api_refs>
+        <description>
+        This sample shows how to use scene transitions from one Activity to another in Lollipop. 
+        Uses a combination of changeImageTransform and changeBounds to transition a grid of images 
+        to an Activity with a large image and detail text.
+        </description>
+        <intro>
+        Android Lollipop has introduced the ability to transition between activities by using a shared element. 
+        This sample demonstrates how to do this using the theme of your application.
+ 
+        See [Defining Custom Animations][1] for all the details on how to do this.
+
+	[1]: https://developer.android.com/training/material/animations.html#Transitions
+        </intro>
+    </metadata>
+
 </sample>
diff --git a/wearable/wear/AgendaData/Application/src/main/AndroidManifest.xml b/wearable/wear/AgendaData/Application/src/main/AndroidManifest.xml
index 284e0e6..aa8a14a 100644
--- a/wearable/wear/AgendaData/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/AgendaData/Application/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
           package="com.example.android.wearable.agendadata">
 
     <uses-sdk android:minSdkVersion="18"
-        android:targetSdkVersion="20" />
+        android:targetSdkVersion="21" />
 
     <uses-permission android:name="android.permission.READ_CALENDAR" />
     <uses-permission android:name="android.permission.READ_CONTACTS" />
diff --git a/wearable/wear/AgendaData/Wearable/src/main/AndroidManifest.xml b/wearable/wear/AgendaData/Wearable/src/main/AndroidManifest.xml
index f2576af..dcab622 100644
--- a/wearable/wear/AgendaData/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/AgendaData/Wearable/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
         package="com.example.android.wearable.agendadata" >
 
     <uses-sdk android:minSdkVersion="20"
-        android:targetSdkVersion="20" />
+        android:targetSdkVersion="21" />
 
     <uses-feature android:name="android.hardware.type.watch" />
 
diff --git a/wearable/wear/DataLayer/Application/src/main/AndroidManifest.xml b/wearable/wear/DataLayer/Application/src/main/AndroidManifest.xml
index 821bc11..6f7e81e 100644
--- a/wearable/wear/DataLayer/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/DataLayer/Application/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
         package="com.example.android.wearable.datalayer" >
 
     <uses-sdk android:minSdkVersion="18"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <uses-feature android:name="android.hardware.camera" android:required="false" />
 
diff --git a/wearable/wear/DataLayer/Wearable/src/main/AndroidManifest.xml b/wearable/wear/DataLayer/Wearable/src/main/AndroidManifest.xml
index 38c0798..4cc9034 100644
--- a/wearable/wear/DataLayer/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/DataLayer/Wearable/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
         package="com.example.android.wearable.datalayer" >
 
     <uses-sdk android:minSdkVersion="20"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <uses-feature android:name="android.hardware.type.watch" />
 
diff --git a/wearable/wear/DelayedConfirmation/Application/src/main/AndroidManifest.xml b/wearable/wear/DelayedConfirmation/Application/src/main/AndroidManifest.xml
index 20b7aab..c9fdccb 100644
--- a/wearable/wear/DelayedConfirmation/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/DelayedConfirmation/Application/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
         package="com.example.android.wearable.delayedconfirmation" >
 
     <uses-sdk android:minSdkVersion="18"
-        android:targetSdkVersion="20" />
+        android:targetSdkVersion="21" />
 
     <application
             android:allowBackup="true"
diff --git a/wearable/wear/DelayedConfirmation/Wearable/src/main/AndroidManifest.xml b/wearable/wear/DelayedConfirmation/Wearable/src/main/AndroidManifest.xml
index b73af62..845c070 100644
--- a/wearable/wear/DelayedConfirmation/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/DelayedConfirmation/Wearable/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
         package="com.example.android.wearable.delayedconfirmation" >
 
     <uses-sdk android:minSdkVersion="20"
-        android:targetSdkVersion="20" />
+        android:targetSdkVersion="21" />
 
     <uses-feature android:name="android.hardware.type.watch" />
 
diff --git a/wearable/wear/ElizaChat/Application/src/main/AndroidManifest.xml b/wearable/wear/ElizaChat/Application/src/main/AndroidManifest.xml
index 98d4d73..8f35c56 100644
--- a/wearable/wear/ElizaChat/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/ElizaChat/Application/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
     package="com.example.android.wearable.elizachat" >
 
     <uses-sdk android:minSdkVersion="18"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <application
         android:allowBackup="true"
diff --git a/wearable/wear/EmbeddedApp/Wearable/src/main/AndroidManifest.xml b/wearable/wear/EmbeddedApp/Wearable/src/main/AndroidManifest.xml
index 2c1d52c..4863d66 100644
--- a/wearable/wear/EmbeddedApp/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/EmbeddedApp/Wearable/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
     package="com.example.android.wearable.embeddedapp" >
 
     <uses-sdk android:minSdkVersion="20"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <uses-feature android:name="android.hardware.type.watch" />
 
diff --git a/wearable/wear/FindMyPhone/Application/src/main/AndroidManifest.xml b/wearable/wear/FindMyPhone/Application/src/main/AndroidManifest.xml
index 0427025..8cb70d1 100644
--- a/wearable/wear/FindMyPhone/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/FindMyPhone/Application/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
           package="com.example.android.wearable.findphone">
 
     <uses-sdk android:minSdkVersion="18"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <uses-permission android:name="android.permission.VIBRATE" />
     <application
diff --git a/wearable/wear/FindMyPhone/Wearable/src/main/AndroidManifest.xml b/wearable/wear/FindMyPhone/Wearable/src/main/AndroidManifest.xml
index fd6d274..18b5209 100644
--- a/wearable/wear/FindMyPhone/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/FindMyPhone/Wearable/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
     package="com.example.android.wearable.findphone" >
 
     <uses-sdk android:minSdkVersion="20"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <uses-permission android:name="android.permission.VIBRATE" />
     <uses-feature android:name="android.hardware.type.watch" />
diff --git a/wearable/wear/Flashlight/Application/src/main/AndroidManifest.xml b/wearable/wear/Flashlight/Application/src/main/AndroidManifest.xml
index 73d1d52..3c50f59 100644
--- a/wearable/wear/Flashlight/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/Flashlight/Application/src/main/AndroidManifest.xml
@@ -19,7 +19,7 @@
     package="com.example.android.wearable.flashlight">
 
     <uses-sdk android:minSdkVersion="18"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <application android:allowBackup="true"
         android:label="@string/app_name">
diff --git a/wearable/wear/Flashlight/Wearable/src/main/AndroidManifest.xml b/wearable/wear/Flashlight/Wearable/src/main/AndroidManifest.xml
index 1800e76..738ba9d 100644
--- a/wearable/wear/Flashlight/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/Flashlight/Wearable/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
           package="com.example.android.wearable.flashlight" >
 
     <uses-sdk android:minSdkVersion="20"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <uses-feature android:name="android.hardware.type.watch" />
 
diff --git a/wearable/wear/Geofencing/Application/src/main/AndroidManifest.xml b/wearable/wear/Geofencing/Application/src/main/AndroidManifest.xml
index b5b57f6..d07a265 100644
--- a/wearable/wear/Geofencing/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/Geofencing/Application/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
           package="com.example.android.wearable.geofencing">
 
     <uses-sdk android:minSdkVersion="18"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
 
diff --git a/wearable/wear/Geofencing/Application/src/main/java/com/example/android/wearable/geofencing/GeofenceTransitionsIntentService.java b/wearable/wear/Geofencing/Application/src/main/java/com/example/android/wearable/geofencing/GeofenceTransitionsIntentService.java
index 5d1ea48..8ae0cbc 100644
--- a/wearable/wear/Geofencing/Application/src/main/java/com/example/android/wearable/geofencing/GeofenceTransitionsIntentService.java
+++ b/wearable/wear/Geofencing/Application/src/main/java/com/example/android/wearable/geofencing/GeofenceTransitionsIntentService.java
@@ -26,11 +26,12 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.util.Log;
+import android.widget.Toast;
 
 import com.google.android.gms.common.ConnectionResult;
 import com.google.android.gms.common.api.GoogleApiClient;
 import com.google.android.gms.location.Geofence;
-import com.google.android.gms.location.LocationClient;
+import com.google.android.gms.location.GeofencingEvent;
 import com.google.android.gms.wearable.PutDataMapRequest;
 import com.google.android.gms.wearable.Wearable;
 
@@ -61,44 +62,46 @@
     /**
      * Handles incoming intents.
      * @param intent The Intent sent by Location Services. This Intent is provided to Location
-     *               Services (inside a PendingIntent) when addGeofences() is called.
+     * Services (inside a PendingIntent) when addGeofences() is called.
      */
     @Override
     protected void onHandleIntent(Intent intent) {
-        // First check for errors.
-        if (LocationClient.hasError(intent)) {
-            int errorCode = LocationClient.getErrorCode(intent);
+        GeofencingEvent geoFenceEvent = GeofencingEvent.fromIntent(intent);
+        if (geoFenceEvent.hasError()) {
+            int errorCode = geoFenceEvent.getErrorCode();
             Log.e(TAG, "Location Services error: " + errorCode);
         } else {
-            // Get the type of geofence transition (i.e. enter or exit in this sample).
-            int transitionType = LocationClient.getGeofenceTransition(intent);
-            // Create a DataItem when a user enters one of the geofences. The wearable app will
-            // receive this and create a notification to prompt him/her to check in.
+
+            int transitionType = geoFenceEvent.getGeofenceTransition();
             if (Geofence.GEOFENCE_TRANSITION_ENTER == transitionType) {
                 // Connect to the Google Api service in preparation for sending a DataItem.
                 mGoogleApiClient.blockingConnect(CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS);
                 // Get the geofence id triggered. Note that only one geofence can be triggered at a
                 // time in this example, but in some cases you might want to consider the full list
                 // of geofences triggered.
-                String triggeredGeofenceId = LocationClient.getTriggeringGeofences(intent).get(0)
+                String triggeredGeoFenceId = geoFenceEvent.getTriggeringGeofences().get(0)
                         .getRequestId();
                 // Create a DataItem with this geofence's id. The wearable can use this to create
                 // a notification.
                 final PutDataMapRequest putDataMapRequest =
                         PutDataMapRequest.create(GEOFENCE_DATA_ITEM_PATH);
-                putDataMapRequest.getDataMap().putString(KEY_GEOFENCE_ID, triggeredGeofenceId);
+                putDataMapRequest.getDataMap().putString(KEY_GEOFENCE_ID, triggeredGeoFenceId);
                 if (mGoogleApiClient.isConnected()) {
                     Wearable.DataApi.putDataItem(
-                        mGoogleApiClient, putDataMapRequest.asPutDataRequest()).await();
+                            mGoogleApiClient, putDataMapRequest.asPutDataRequest()).await();
                 } else {
                     Log.e(TAG, "Failed to send data item: " + putDataMapRequest
-                             + " - Client disconnected from Google Play Services");
+                            + " - Client disconnected from Google Play Services");
                 }
+                Toast.makeText(this, getString(R.string.entering_geofence),
+                        Toast.LENGTH_SHORT).show();
                 mGoogleApiClient.disconnect();
             } else if (Geofence.GEOFENCE_TRANSITION_EXIT == transitionType) {
                 // Delete the data item when leaving a geofence region.
                 mGoogleApiClient.blockingConnect(CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS);
                 Wearable.DataApi.deleteDataItems(mGoogleApiClient, GEOFENCE_DATA_ITEM_URI).await();
+                Toast.makeText(this, getString(R.string.exiting_geofence),
+                        Toast.LENGTH_SHORT).show();
                 mGoogleApiClient.disconnect();
             }
         }
diff --git a/wearable/wear/Geofencing/Application/src/main/java/com/example/android/wearable/geofencing/MainActivity.java b/wearable/wear/Geofencing/Application/src/main/java/com/example/android/wearable/geofencing/MainActivity.java
index baef217..350c9c5 100644
--- a/wearable/wear/Geofencing/Application/src/main/java/com/example/android/wearable/geofencing/MainActivity.java
+++ b/wearable/wear/Geofencing/Application/src/main/java/com/example/android/wearable/geofencing/MainActivity.java
@@ -39,17 +39,16 @@
 import com.google.android.gms.common.ConnectionResult;
 import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks;
 import com.google.android.gms.common.GooglePlayServicesUtil;
+import com.google.android.gms.common.api.GoogleApiClient;
 import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
 import com.google.android.gms.location.Geofence;
-import com.google.android.gms.location.LocationClient;
-import com.google.android.gms.location.LocationClient.OnAddGeofencesResultListener;
-import com.google.android.gms.location.LocationStatusCodes;
+import com.google.android.gms.location.LocationServices;
 
 import java.util.ArrayList;
 import java.util.List;
 
 public class MainActivity extends Activity implements ConnectionCallbacks,
-        OnConnectionFailedListener, OnAddGeofencesResultListener {
+        OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {
 
     // Internal List of Geofence objects. In a real app, these might be provided by an API based on
     // locations within the user's proximity.
@@ -62,35 +61,39 @@
     // Persistent storage for geofences.
     private SimpleGeofenceStore mGeofenceStorage;
 
-    private LocationClient mLocationClient;
+    private LocationServices mLocationService;
     // Stores the PendingIntent used to request geofence monitoring.
     private PendingIntent mGeofenceRequestIntent;
+    private GoogleApiClient mApiClient;
 
     // Defines the allowable request types (in this example, we only add geofences).
     private enum REQUEST_TYPE {ADD}
     private REQUEST_TYPE mRequestType;
-    // Flag that indicates if a request is underway.
-    private boolean mInProgress;
-
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         // Rather than displayng this activity, simply display a toast indicating that the geofence
         // service is being created. This should happen in less than a second.
-        Toast.makeText(this, getString(R.string.start_geofence_service), Toast.LENGTH_SHORT).show();
+        if (!isGooglePlayServicesAvailable()) {
+            Log.e(TAG, "Google Play services unavailable.");
+            finish();
+            return;
+        }
+
+        mApiClient = new GoogleApiClient.Builder(this)
+                .addApi(LocationServices.API)
+                .addConnectionCallbacks(this)
+                .addOnConnectionFailedListener(this)
+                .build();
+
+        mApiClient.connect();
 
         // Instantiate a new geofence storage area.
         mGeofenceStorage = new SimpleGeofenceStore(this);
         // Instantiate the current List of geofences.
         mGeofenceList = new ArrayList<Geofence>();
-        // Start with the request flag set to false.
-        mInProgress = false;
-
         createGeofences();
-        addGeofences();
-
-        finish();
     }
 
     /**
@@ -123,37 +126,9 @@
         mGeofenceList.add(mYerbaBuenaGeofence.toGeofence());
     }
 
-    /**
-     * Start a request for geofence monitoring by calling LocationClient.connect().
-     */
-    public void addGeofences() {
-        // Start a request to add geofences.
-        mRequestType = REQUEST_TYPE.ADD;
-        // Test for Google Play services after setting the request type.
-        if (!isGooglePlayServicesAvailable()) {
-            Log.e(TAG, "Unable to add geofences - Google Play services unavailable.");
-            return;
-        }
-        // Create a new location client object. Since this activity class implements
-        // ConnectionCallbacks and OnConnectionFailedListener, it can be used as the listener for
-        // both parameters.
-        mLocationClient = new LocationClient(this, this, this);
-        // If a request is not already underway.
-        if (!mInProgress) {
-            // Indicate that a request is underway.
-            mInProgress = true;
-            // Request a connection from the client to Location Services.
-            mLocationClient.connect();
-        // A request is already underway, so disconnect the client and retry the request.
-        } else {
-            mLocationClient.disconnect();
-            mLocationClient.connect();
-        }
-    }
 
     @Override
     public void onConnectionFailed(ConnectionResult connectionResult) {
-        mInProgress = false;
         // If the error has a resolution, start a Google Play services activity to resolve it.
         if (connectionResult.hasResolution()) {
             try {
@@ -168,15 +143,8 @@
         }
     }
 
-    /**
-     * Called by Location Services if the location client disconnects.
-     */
     @Override
     public void onDisconnected() {
-        // Turn off the request flag.
-        mInProgress = false;
-        // Destroy the current location client.
-        mLocationClient = null;
     }
 
     /**
@@ -184,32 +152,22 @@
      */
     @Override
     public void onConnected(Bundle connectionHint) {
-        // Use mRequestType to determine what action to take. Only ADD is used in this sample.
-        if (REQUEST_TYPE.ADD == mRequestType) {
-            // Get the PendingIntent for the geofence monitoring request.
-            mGeofenceRequestIntent = getGeofenceTransitionPendingIntent();
-            // Send a request to add the current geofences.
-            mLocationClient.addGeofences(mGeofenceList, mGeofenceRequestIntent, this);
+        // Get the PendingIntent for the geofence monitoring request.
+        // Send a request to add the current geofences.
+        mGeofenceRequestIntent = getGeofenceTransitionPendingIntent();
+        LocationServices.GeofencingApi.addGeofences(mApiClient, mGeofenceList,
+                mGeofenceRequestIntent);
+        Toast.makeText(this, getString(R.string.start_geofence_service), Toast.LENGTH_SHORT).show();
+        finish();
+    }
+
+    @Override
+    public void onConnectionSuspended(int i) {
+        if (null != mGeofenceRequestIntent) {
+            LocationServices.GeofencingApi.removeGeofences(mApiClient, mGeofenceRequestIntent);
         }
     }
 
-    /**
-     * Called when request to add geofences is complete, with a result status code.
-     */
-    @Override
-    public void onAddGeofencesResult(int statusCode, String[] geofenceRequestIds) {
-        // Log if adding the geofences was successful.
-        if (LocationStatusCodes.SUCCESS == statusCode) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Added geofences successfully.");
-            }
-        } else {
-            Log.e(TAG, "Failed to add geofences. Status code: " + statusCode);
-        }
-        // Turn off the in progress flag and disconnect the client.
-        mInProgress = false;
-        mLocationClient.disconnect();
-    }
 
     /**
      * Checks if Google Play services is available.
diff --git a/wearable/wear/Geofencing/Application/src/main/res/values/strings.xml b/wearable/wear/Geofencing/Application/src/main/res/values/strings.xml
index ad9717b..610661e 100644
--- a/wearable/wear/Geofencing/Application/src/main/res/values/strings.xml
+++ b/wearable/wear/Geofencing/Application/src/main/res/values/strings.xml
@@ -16,4 +16,6 @@
 
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="start_geofence_service">Starting geofence transition service</string>
+    <string name="entering_geofence">Entering the GeoFence zone</string>
+    <string name="exiting_geofence">Exiting the GeoFence zone</string>
 </resources>
diff --git a/wearable/wear/Geofencing/Wearable/src/main/AndroidManifest.xml b/wearable/wear/Geofencing/Wearable/src/main/AndroidManifest.xml
index 97ce90e..082f396 100644
--- a/wearable/wear/Geofencing/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/Geofencing/Wearable/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
         package="com.example.android.wearable.geofencing" >
 
     <uses-sdk android:minSdkVersion="20"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <uses-feature android:name="android.hardware.type.watch" />
 
diff --git a/wearable/wear/GridViewPager/Application/src/main/AndroidManifest.xml b/wearable/wear/GridViewPager/Application/src/main/AndroidManifest.xml
index add48f1..8060bc8 100644
--- a/wearable/wear/GridViewPager/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/GridViewPager/Application/src/main/AndroidManifest.xml
@@ -19,7 +19,7 @@
     package="com.example.android.wearable.gridviewpager">
 
     <uses-sdk android:minSdkVersion="18"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <application android:allowBackup="true"
         android:label="@string/app_name">
diff --git a/wearable/wear/GridViewPager/Wearable/src/main/AndroidManifest.xml b/wearable/wear/GridViewPager/Wearable/src/main/AndroidManifest.xml
index 3f9c4b1..5c362dc 100644
--- a/wearable/wear/GridViewPager/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/GridViewPager/Wearable/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
     package="com.example.android.wearable.gridviewpager" >
 
     <uses-sdk android:minSdkVersion="20"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <uses-feature android:name="android.hardware.type.watch" />
 
diff --git a/wearable/wear/GridViewPager/Wearable/src/main/java/com/example/android/wearable/gridviewpager/CustomFragment.java b/wearable/wear/GridViewPager/Wearable/src/main/java/com/example/android/wearable/gridviewpager/CustomFragment.java
new file mode 100644
index 0000000..aff3665
--- /dev/null
+++ b/wearable/wear/GridViewPager/Wearable/src/main/java/com/example/android/wearable/gridviewpager/CustomFragment.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 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.gridviewpager;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class CustomFragment extends Fragment {
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.custom_fragment, container, false);
+    }
+}
diff --git a/wearable/wear/GridViewPager/Wearable/src/main/java/com/example/android/wearable/gridviewpager/SampleGridPagerAdapter.java b/wearable/wear/GridViewPager/Wearable/src/main/java/com/example/android/wearable/gridviewpager/SampleGridPagerAdapter.java
index 8f9bcf9..4d329c5 100644
--- a/wearable/wear/GridViewPager/Wearable/src/main/java/com/example/android/wearable/gridviewpager/SampleGridPagerAdapter.java
+++ b/wearable/wear/GridViewPager/Wearable/src/main/java/com/example/android/wearable/gridviewpager/SampleGridPagerAdapter.java
@@ -19,22 +19,104 @@
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.TransitionDrawable;
+import android.os.AsyncTask;
+import android.support.v4.util.LruCache;
 import android.support.wearable.view.CardFragment;
 import android.support.wearable.view.FragmentGridPagerAdapter;
-import android.support.wearable.view.ImageReference;
-import android.view.Gravity;
+import android.support.wearable.view.GridPagerAdapter;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
- * Constructs fragments as requested by the GridViewPager. For each row a
- * different background is provided.
+ * Constructs fragments as requested by the GridViewPager. For each row a different background is
+ * provided.
+ * <p>
+ * Always avoid loading resources from the main thread. In this sample, the background images are
+ * loaded from an background task and then updated using {@link #notifyRowBackgroundChanged(int)}
+ * and {@link #notifyPageBackgroundChanged(int, int)}.
  */
 public class SampleGridPagerAdapter extends FragmentGridPagerAdapter {
+    private static final int TRANSITION_DURATION_MILLIS = 100;
 
     private final Context mContext;
+    private List<Row> mRows;
+    private ColorDrawable mDefaultBg;
+
+    private ColorDrawable mClearBg;
 
     public SampleGridPagerAdapter(Context ctx, FragmentManager fm) {
         super(fm);
         mContext = ctx;
+
+        mRows = new ArrayList<SampleGridPagerAdapter.Row>();
+
+        mRows.add(new Row(cardFragment(R.string.welcome_title, R.string.welcome_text)));
+        mRows.add(new Row(cardFragment(R.string.about_title, R.string.about_text)));
+        mRows.add(new Row(
+                cardFragment(R.string.cards_title, R.string.cards_text),
+                cardFragment(R.string.expansion_title, R.string.expansion_text)));
+        mRows.add(new Row(
+                cardFragment(R.string.backgrounds_title, R.string.backgrounds_text),
+                cardFragment(R.string.columns_title, R.string.columns_text)));
+        mRows.add(new Row(new CustomFragment()));
+        mRows.add(new Row(cardFragment(R.string.dismiss_title, R.string.dismiss_text)));
+        mDefaultBg = new ColorDrawable(R.color.dark_grey);
+        mClearBg = new ColorDrawable(android.R.color.transparent);
+    }
+
+    LruCache<Integer, Drawable> mRowBackgrounds = new LruCache<Integer, Drawable>(3) {
+        @Override
+        protected Drawable create(final Integer row) {
+            int resid = BG_IMAGES[row % BG_IMAGES.length];
+            new DrawableLoadingTask(mContext) {
+                @Override
+                protected void onPostExecute(Drawable result) {
+                    TransitionDrawable background = new TransitionDrawable(new Drawable[] {
+                            mDefaultBg,
+                            result
+                    });
+                    mRowBackgrounds.put(row, background);
+                    notifyRowBackgroundChanged(row);
+                    background.startTransition(TRANSITION_DURATION_MILLIS);
+                }
+            }.execute(resid);
+            return mDefaultBg;
+        }
+    };
+
+    LruCache<Point, Drawable> mPageBackgrounds = new LruCache<Point, Drawable>(3) {
+        @Override
+        protected Drawable create(final Point page) {
+            // place bugdroid as the background at row 2, column 1
+            if (page.y == 2 && page.x == 1) {
+                int resid = R.drawable.bugdroid_large;
+                new DrawableLoadingTask(mContext) {
+                    @Override
+                    protected void onPostExecute(Drawable result) {
+                        TransitionDrawable background = new TransitionDrawable(new Drawable[] {
+                                mClearBg,
+                                result
+                        });
+                        mPageBackgrounds.put(page, background);
+                        notifyPageBackgroundChanged(page.y, page.x);
+                        background.startTransition(TRANSITION_DURATION_MILLIS);
+                    }
+                }.execute(resid);
+            }
+            return GridPagerAdapter.BACKGROUND_NONE;
+        }
+    };
+
+    private Fragment cardFragment(int titleRes, int textRes) {
+        Resources res = mContext.getResources();
+        return CardFragment.create(res.getText(titleRes), res.getText(textRes));
     }
 
     static final int[] BG_IMAGES = new int[] {
@@ -45,90 +127,67 @@
             R.drawable.debug_background_5
     };
 
-    /** A simple container for static data in each page */
-    private static class Page {
-        int titleRes;
-        int textRes;
-        int iconRes;
-        int cardGravity = Gravity.BOTTOM;
-        boolean expansionEnabled = true;
-        float expansionFactor = 1.0f;
-        int expansionDirection = CardFragment.EXPAND_DOWN;
+    /** A convenient container for a row of fragments. */
+    private class Row {
+        final List<Fragment> columns = new ArrayList<Fragment>();
 
-        public Page(int titleRes, int textRes, boolean expansion) {
-            this(titleRes, textRes, 0);
-            this.expansionEnabled = expansion;
+        public Row(Fragment... fragments) {
+            for (Fragment f : fragments) {
+                add(f);
+            }
         }
 
-        public Page(int titleRes, int textRes, boolean expansion, float expansionFactor) {
-            this(titleRes, textRes, 0);
-            this.expansionEnabled = expansion;
-            this.expansionFactor = expansionFactor;
+        public void add(Fragment f) {
+            columns.add(f);
         }
 
-        public Page(int titleRes, int textRes, int iconRes) {
-            this.titleRes = titleRes;
-            this.textRes = textRes;
-            this.iconRes = iconRes;
+        Fragment getColumn(int i) {
+            return columns.get(i);
         }
 
-        public Page(int titleRes, int textRes, int iconRes, int gravity) {
-            this.titleRes = titleRes;
-            this.textRes = textRes;
-            this.iconRes = iconRes;
-            this.cardGravity = gravity;
+        public int getColumnCount() {
+            return columns.size();
         }
     }
 
-    private final Page[][] PAGES = {
-            {
-                    new Page(R.string.welcome_title, R.string.welcome_text, R.drawable.bugdroid,
-                            Gravity.CENTER_VERTICAL),
-            },
-            {
-                    new Page(R.string.about_title, R.string.about_text, false),
-            },
-            {
-                    new Page(R.string.cards_title, R.string.cards_text, true, 2),
-                    new Page(R.string.expansion_title, R.string.expansion_text, true, 10),
-            },
-            {
-                    new Page(R.string.backgrounds_title, R.string.backgrounds_text, true, 2),
-                    new Page(R.string.columns_title, R.string.columns_text, true, 2)
-            },
-            {
-                    new Page(R.string.dismiss_title, R.string.dismiss_text, R.drawable.bugdroid,
-                            Gravity.CENTER_VERTICAL),
-            },
-
-    };
-
     @Override
     public Fragment getFragment(int row, int col) {
-        Page page = PAGES[row][col];
-        String title = page.titleRes != 0 ? mContext.getString(page.titleRes) : null;
-        String text = page.textRes != 0 ? mContext.getString(page.textRes) : null;
-        CardFragment fragment = CardFragment.create(title, text, page.iconRes);
-        // Advanced settings
-        fragment.setCardGravity(page.cardGravity);
-        fragment.setExpansionEnabled(page.expansionEnabled);
-        fragment.setExpansionDirection(page.expansionDirection);
-        fragment.setExpansionFactor(page.expansionFactor);
-        return fragment;
+        Row adapterRow = mRows.get(row);
+        return adapterRow.getColumn(col);
     }
 
     @Override
-    public ImageReference getBackground(int row, int column) {
-        return ImageReference.forDrawable(BG_IMAGES[row % BG_IMAGES.length]);
+    public Drawable getBackgroundForRow(final int row) {
+        return mRowBackgrounds.get(row);
+    }
+
+    @Override
+    public Drawable getBackgroundForPage(final int row, final int column) {
+        return mPageBackgrounds.get(new Point(column, row));
     }
 
     @Override
     public int getRowCount() {
-        return PAGES.length;
+        return mRows.size();
     }
 
     @Override
     public int getColumnCount(int rowNum) {
-        return PAGES[rowNum].length;
+        return mRows.get(rowNum).getColumnCount();
+    }
+
+    class DrawableLoadingTask extends AsyncTask<Integer, Void, Drawable> {
+        private static final String TAG = "Loader";
+        private Context context;
+
+        DrawableLoadingTask(Context context) {
+            this.context = context;
+        }
+
+        @Override
+        protected Drawable doInBackground(Integer... params) {
+            Log.d(TAG, "Loading asset 0x" + Integer.toHexString(params[0]));
+            return context.getResources().getDrawable(params[0]);
+        }
     }
 }
diff --git a/wearable/wear/GridViewPager/Wearable/src/main/res/drawable-nodpi/bugdroid_large.png b/wearable/wear/GridViewPager/Wearable/src/main/res/drawable-nodpi/bugdroid_large.png
new file mode 100644
index 0000000..7b393b2
--- /dev/null
+++ b/wearable/wear/GridViewPager/Wearable/src/main/res/drawable-nodpi/bugdroid_large.png
Binary files differ
diff --git a/wearable/wear/GridViewPager/Wearable/src/main/res/drawable/gradient.xml b/wearable/wear/GridViewPager/Wearable/src/main/res/drawable/gradient.xml
new file mode 100644
index 0000000..7077043
--- /dev/null
+++ b/wearable/wear/GridViewPager/Wearable/src/main/res/drawable/gradient.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle" >
+
+    <gradient
+        android:angle="45"
+        android:endColor="#87CEEB"
+        android:centerColor="#768087"
+        android:startColor="#000"
+        android:type="linear" />
+
+</shape>
diff --git a/wearable/wear/GridViewPager/Wearable/src/main/res/drawable/shape.xml b/wearable/wear/GridViewPager/Wearable/src/main/res/drawable/shape.xml
new file mode 100644
index 0000000..a6306c7
--- /dev/null
+++ b/wearable/wear/GridViewPager/Wearable/src/main/res/drawable/shape.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle" >
+
+    <stroke
+        android:dashGap="4dp"
+        android:dashWidth="10dp"
+        android:width="6dp"
+        android:color="@color/black" />
+
+    <solid android:color="@color/white" />
+
+    <padding
+        android:bottom="20dp"
+        android:left="20dp"
+        android:right="20dp"
+        android:top="20dp" />
+
+</shape>
diff --git a/wearable/wear/GridViewPager/Wearable/src/main/res/layout/custom_fragment.xml b/wearable/wear/GridViewPager/Wearable/src/main/res/layout/custom_fragment.xml
new file mode 100644
index 0000000..13b02f2
--- /dev/null
+++ b/wearable/wear/GridViewPager/Wearable/src/main/res/layout/custom_fragment.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@drawable/gradient" >
+
+    <TextView
+        android:id="@+id/text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_margin="8dp"
+        android:background="@drawable/shape"
+        android:text="@string/custom_fragment_text" 
+        android:textColor="@color/primary_text_light"/>
+
+</FrameLayout>
diff --git a/wearable/wear/GridViewPager/Wearable/src/main/res/values/strings.xml b/wearable/wear/GridViewPager/Wearable/src/main/res/values/strings.xml
index 404119b..ab4e663 100644
--- a/wearable/wear/GridViewPager/Wearable/src/main/res/values/strings.xml
+++ b/wearable/wear/GridViewPager/Wearable/src/main/res/values/strings.xml
@@ -18,39 +18,25 @@
 
     <string name="app_name">GridViewPager Sample</string>
     <string name="welcome_title">GridViewPager</string>
-    <string name="welcome_text">Welcome!</string>
+    <string name="welcome_text">Sample App</string>
 
     <string name="about_title">About</string>
-    <string name="about_text">Content is organized into multiple pages. Swipe
-        between cards to view other content.</string>
+    <string name="about_text">Content is organized into multiple pages. Swipe between cards to view other content.</string>
 
     <string name="cards_title">Cards</string>
-    <string name="cards_text">Each page is created using a CardFragment. A
-        layout is placed inside the card and the rest is handled
-        automatically.</string>
+    <string name="cards_text">Each page is created using a CardFragment. A layout is placed inside the card and the rest is handled automatically.</string>
 
     <string name="expansion_title">Expansion</string>
-    <string name="expansion_text">By default, each card will grow taller to
-        accommodate extra content. Tall cards can be scrolled through
-        like any scrollable view. The maximum height is controlled by
-        setExpansionFactor() with a default of 10 pages. After that
-        you\'ll notice a faded edge to indicate there is more. Expansion
-        can be disabled completely using setExpansionEnabled(false).
-        With this, the content will be clipped if it\'s taller than one
-        page.</string>
+    <string name="expansion_text">By default, each card will grow taller to accommodate extra content. Tall cards can be scrolled through like any scrollable view. The maximum height is controlled by setExpansionFactor() with a default of 10 pages. After that you\'ll notice a faded edge to indicate there is more. Expansion can be disabled completely using setExpansionEnabled(false). With this, the content will be clipped if it\'s taller than one page.</string>
 
     <string name="backgrounds_title">Backgrounds</string>
-    <string name="backgrounds_text">Backgrounds are supplied by the adapter\'s
-        getBackground method. Parallax and crossfade effects are applied
-        automatically.</string>
+    <string name="backgrounds_text">Backgrounds are supplied by the adapter\'s getBackground method. Parallax and crossfade effects are applied automatically.</string>
 
     <string name="columns_title">Columns</string>
-    <string name="columns_text">When moving between rows, the pager always
-        returns to column 0. This is adjustable in the adapter. See
-        method getCurrentColumnForRow().</string>
+    <string name="columns_text">When moving between rows, the pager always returns to column 0. This is adjustable in the adapter. See method getCurrentColumnForRow().</string>
 
     <string name="dismiss_title">Dismiss</string>
-    <string name="dismiss_text">To exit the application, swipe from left to
-        right.</string>
+    <string name="dismiss_text">To exit the application, swipe from left to right.</string>
+    <string name="custom_fragment_text">"GridViewPager will accept any fragment. This is an example of a custom fragment with it's own background."</string>
 
 </resources>
diff --git a/wearable/wear/JumpingJack/Application/src/main/AndroidManifest.xml b/wearable/wear/JumpingJack/Application/src/main/AndroidManifest.xml
index 7610f59..88e559a 100644
--- a/wearable/wear/JumpingJack/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/JumpingJack/Application/src/main/AndroidManifest.xml
@@ -19,7 +19,7 @@
     package="com.example.android.wearable.jumpingjack">
 
     <uses-sdk android:minSdkVersion="18"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
     <uses-permission android:name="android.permission.VIBRATE"/>
 
     <application android:allowBackup="true"
diff --git a/wearable/wear/JumpingJack/Wearable/src/main/AndroidManifest.xml b/wearable/wear/JumpingJack/Wearable/src/main/AndroidManifest.xml
index f123f77..02b7a4f 100644
--- a/wearable/wear/JumpingJack/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/JumpingJack/Wearable/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
           package="com.example.android.wearable.jumpingjack">
 
    <uses-sdk android:minSdkVersion="20"
-             android:targetSdkVersion="20" />
+             android:targetSdkVersion="21" />
 
     <uses-feature android:name="android.hardware.type.watch" />
 
diff --git a/wearable/wear/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/MainActivity.java b/wearable/wear/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/MainActivity.java
index cdaaf6e..f1589c7 100644
--- a/wearable/wear/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/MainActivity.java
+++ b/wearable/wear/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/MainActivity.java
@@ -99,7 +99,7 @@
         mSecondIndicator = (ImageView) findViewById(R.id.indicator_1);
         final PagerAdapter adapter = new PagerAdapter(getFragmentManager());
         mCounterPage = new CounterFragment();
-        mSettingPage = new SettingsFragment(this);
+        mSettingPage = new SettingsFragment();
         adapter.addFragment(mCounterPage);
         adapter.addFragment(mSettingPage);
         setIndicator(0);
diff --git a/wearable/wear/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/fragments/SettingsFragment.java b/wearable/wear/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/fragments/SettingsFragment.java
index fffe8fb..771abd3 100644
--- a/wearable/wear/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/fragments/SettingsFragment.java
+++ b/wearable/wear/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/fragments/SettingsFragment.java
@@ -31,22 +31,15 @@
  */
 public class SettingsFragment extends Fragment {
 
-    private Button mButton;
-    private MainActivity mMainActivity;
-
-    public SettingsFragment(MainActivity mainActivity) {
-        mMainActivity = mainActivity;
-    }
-
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
         View view = inflater.inflate(R.layout.setting_layout, container, false);
-        mButton = (Button) view.findViewById(R.id.btn);
-        mButton.setOnClickListener(new View.OnClickListener() {
+        Button button = (Button) view.findViewById(R.id.btn);
+        button.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                mMainActivity.resetCounter();
+                ((MainActivity) getActivity()).resetCounter();
             }
         });
         return view;
diff --git a/wearable/wear/Notifications/Application/src/main/AndroidManifest.xml b/wearable/wear/Notifications/Application/src/main/AndroidManifest.xml
index c7b2da7..3f1274d 100644
--- a/wearable/wear/Notifications/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/Notifications/Application/src/main/AndroidManifest.xml
@@ -17,9 +17,10 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.example.android.support.wearable.notifications" >
 
-
     <uses-sdk android:minSdkVersion="18"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
+
+    <uses-permission android:name="android.permission.VIBRATE" />
 
     <application
             android:allowBackup="true"
diff --git a/wearable/wear/Notifications/Application/src/main/res/values/colors.xml b/wearable/wear/Notifications/Application/src/main/res/values/colors.xml
index 9464085..fbcf956 100644
--- a/wearable/wear/Notifications/Application/src/main/res/values/colors.xml
+++ b/wearable/wear/Notifications/Application/src/main/res/values/colors.xml
@@ -15,5 +15,5 @@
 -->
 
 <resources>
-    <color name="divider_text">@android:color/holo_blue_bright</color>
+    <color name="divider_text">@android:color/holo_blue_dark</color>
 </resources>
diff --git a/wearable/wear/Notifications/Wearable/src/main/AndroidManifest.xml b/wearable/wear/Notifications/Wearable/src/main/AndroidManifest.xml
index 57cd7c4..34a29ff 100644
--- a/wearable/wear/Notifications/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/Notifications/Wearable/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
         package="com.example.android.support.wearable.notifications" >
 
     <uses-sdk android:minSdkVersion="20"
-        android:targetSdkVersion="20" />
+        android:targetSdkVersion="21" />
 
     <uses-feature android:name="android.hardware.type.watch" />
 
diff --git a/wearable/wear/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/WearableListItemLayout.java b/wearable/wear/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/WearableListItemLayout.java
index 773dfe4..4ec554c 100644
--- a/wearable/wear/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/WearableListItemLayout.java
+++ b/wearable/wear/Notifications/Wearable/src/main/java/com/example/android/support/wearable/notifications/WearableListItemLayout.java
@@ -24,7 +24,8 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-public class WearableListItemLayout extends LinearLayout implements WearableListView.Item {
+public class WearableListItemLayout extends LinearLayout
+        implements WearableListView.OnCenterProximityListener {
 
     private final float mFadedTextAlpha;
     private final int mFadedCircleColor;
@@ -56,35 +57,13 @@
     }
 
     @Override
-    public float getProximityMinValue() {
-        return 1f;
-    }
-
-    @Override
-    public float getProximityMaxValue() {
-        return 1.6f;
-    }
-
-    @Override
-    public float getCurrentProximityValue() {
-        return mScale;
-    }
-
-    @Override
-    public void setScalingAnimatorValue(float scale) {
-        mScale = scale;
-        mCircle.setScaleX(scale);
-        mCircle.setScaleY(scale);
-    }
-
-    @Override
-    public void onScaleUpStart() {
+    public void onCenterPosition(boolean animate) {
         mName.setAlpha(1f);
         ((GradientDrawable) mCircle.getDrawable()).setColor(mChosenCircleColor);
     }
 
     @Override
-    public void onScaleDownStart() {
+    public void onNonCenterPosition(boolean animate) {
         ((GradientDrawable) mCircle.getDrawable()).setColor(mFadedCircleColor);
         mName.setAlpha(mFadedTextAlpha);
     }
diff --git a/wearable/wear/Notifications/template-params.xml b/wearable/wear/Notifications/template-params.xml
index bf2087a..3b9dda1 100644
--- a/wearable/wear/Notifications/template-params.xml
+++ b/wearable/wear/Notifications/template-params.xml
@@ -18,7 +18,7 @@
 
 
 <sample>
-    <name>Notifications</name>
+    <name>Wearable Notifications</name>
     <group>Wearable</group>
     <package>com.example.android.support.wearable.notifications</package>
 
diff --git a/wearable/wear/Quiz/Application/src/main/AndroidManifest.xml b/wearable/wear/Quiz/Application/src/main/AndroidManifest.xml
index 0d14a71..55b666f 100644
--- a/wearable/wear/Quiz/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/Quiz/Application/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
         package="com.example.android.wearable.quiz" >
 
     <uses-sdk android:minSdkVersion="18"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <application
             android:allowBackup="true"
diff --git a/wearable/wear/Quiz/Wearable/src/main/AndroidManifest.xml b/wearable/wear/Quiz/Wearable/src/main/AndroidManifest.xml
index fd20def..fbc7492 100644
--- a/wearable/wear/Quiz/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/Quiz/Wearable/src/main/AndroidManifest.xml
@@ -19,7 +19,7 @@
 
 
     <uses-sdk android:minSdkVersion="20"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <uses-feature android:name="android.hardware.type.watch" />
 
diff --git a/wearable/wear/RecipeAssistant/Application/src/main/AndroidManifest.xml b/wearable/wear/RecipeAssistant/Application/src/main/AndroidManifest.xml
index a9199ed..1786d27 100644
--- a/wearable/wear/RecipeAssistant/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/RecipeAssistant/Application/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
     package="com.example.android.wearable.recipeassistant" >
 
     <uses-sdk android:minSdkVersion="18"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <application
         android:allowBackup="true"
diff --git a/wearable/wear/SkeletonWearableApp/Application/src/main/AndroidManifest.xml b/wearable/wear/SkeletonWearableApp/Application/src/main/AndroidManifest.xml
index 757c92e..25ed258 100644
--- a/wearable/wear/SkeletonWearableApp/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/SkeletonWearableApp/Application/src/main/AndroidManifest.xml
@@ -19,7 +19,7 @@
     package="com.example.android.google.wearable.app">
 
     <uses-sdk android:minSdkVersion="18"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <application android:allowBackup="true"
         android:label="@string/app_name">
diff --git a/wearable/wear/SkeletonWearableApp/Wearable/src/main/AndroidManifest.xml b/wearable/wear/SkeletonWearableApp/Wearable/src/main/AndroidManifest.xml
index bf1c1a4..f99d785 100644
--- a/wearable/wear/SkeletonWearableApp/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/SkeletonWearableApp/Wearable/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
         package="com.example.android.google.wearable.app" >
 
     <uses-sdk android:minSdkVersion="20"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <uses-feature android:name="android.hardware.type.watch" />
 
diff --git a/wearable/wear/SkeletonWearableApp/Wearable/src/main/java/com/example/android/google/wearable/app/GridExampleActivity.java b/wearable/wear/SkeletonWearableApp/Wearable/src/main/java/com/example/android/google/wearable/app/GridExampleActivity.java
index 0a88c04..80af2a6 100644
--- a/wearable/wear/SkeletonWearableApp/Wearable/src/main/java/com/example/android/google/wearable/app/GridExampleActivity.java
+++ b/wearable/wear/SkeletonWearableApp/Wearable/src/main/java/com/example/android/google/wearable/app/GridExampleActivity.java
@@ -19,17 +19,21 @@
 import android.app.Activity;
 import android.app.Fragment;
 import android.app.FragmentManager;
+import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Point;
 import android.graphics.Typeface;
+import android.graphics.Paint.Align;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.support.wearable.view.CardFragment;
 import android.support.wearable.view.FragmentGridPagerAdapter;
 import android.support.wearable.view.GridViewPager;
-import android.support.wearable.view.ImageReference;
+
 import java.util.HashMap;
 import java.util.Map;
 
@@ -46,16 +50,18 @@
         super.onCreate(savedInstanceState);
         setContentView(R.layout.grid_activity);
         mPager = (GridViewPager) findViewById(R.id.fragment_container);
-        mAdapter = new MainAdapter(getFragmentManager());
+        mAdapter = new MainAdapter(this, getFragmentManager());
         mPager.setAdapter(mAdapter);
 
     }
 
     private static class MainAdapter extends FragmentGridPagerAdapter{
-        Map<Point, ImageReference> mBackgrounds = new HashMap<Point, ImageReference>();
+        Map<Point, Drawable> mBackgrounds = new HashMap<Point, Drawable>();
+        private Context mContext;
 
-        public MainAdapter(FragmentManager fm) {
+        public MainAdapter(Context ctx, FragmentManager fm) {
             super(fm);
+            mContext = ctx;
         }
 
         @Override
@@ -74,10 +80,10 @@
         }
 
         @Override
-        public ImageReference getBackground(int row, int column) {
+        public Drawable getBackgroundForPage(int row, int column) {
             Point pt = new Point(column, row);
-            ImageReference ref = mBackgrounds.get(pt);
-            if (ref == null) {
+            Drawable drawable = mBackgrounds.get(pt);
+            if (drawable == null) {
                 Bitmap bm = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
                 Canvas c = new Canvas(bm);
                 Paint p = new Paint();
@@ -87,11 +93,12 @@
                 p.setTypeface(Typeface.DEFAULT);
                 p.setTextSize(64);
                 p.setColor(Color.LTGRAY);
-                c.drawText(column+ "-" + row, 20, 100, p);
-                ref = ImageReference.forBitmap(bm);
-                mBackgrounds.put(pt, ref);
+                p.setTextAlign(Align.CENTER);
+                c.drawText(column+ "-" + row, 100, 100, p);
+                drawable = new BitmapDrawable(mContext.getResources(), bm);
+                mBackgrounds.put(pt, drawable);
             }
-            return ref;
+            return drawable;
         }
     }
 
diff --git a/wearable/wear/SpeedTracker/Application/.gitignore b/wearable/wear/SpeedTracker/Application/.gitignore
new file mode 100644
index 0000000..6eb878d
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Application/.gitignore
@@ -0,0 +1,16 @@
+# 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.
+src/template/
+src/common/
+build.gradle
diff --git a/wearable/wear/SpeedTracker/Application/src/main/AndroidManifest.xml b/wearable/wear/SpeedTracker/Application/src/main/AndroidManifest.xml
index 2a64592..44284d4 100644
--- a/wearable/wear/SpeedTracker/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/SpeedTracker/Application/src/main/AndroidManifest.xml
@@ -13,7 +13,7 @@
         android:glEsVersion="0x00020000" android:required="true"/>
     <uses-sdk
         android:minSdkVersion="18"
-        android:targetSdkVersion="20" />
+        android:targetSdkVersion="21" />
 
     <application
         android:name=".PhoneApplication"
diff --git a/wearable/wear/SpeedTracker/Shared/.gitignore b/wearable/wear/SpeedTracker/Shared/.gitignore
new file mode 100644
index 0000000..6eb878d
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Shared/.gitignore
@@ -0,0 +1,16 @@
+# 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.
+src/template/
+src/common/
+build.gradle
diff --git a/wearable/wear/SpeedTracker/Wearable/.gitignore b/wearable/wear/SpeedTracker/Wearable/.gitignore
new file mode 100644
index 0000000..6eb878d
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/.gitignore
@@ -0,0 +1,16 @@
+# 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.
+src/template/
+src/common/
+build.gradle
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/AndroidManifest.xml b/wearable/wear/SpeedTracker/Wearable/src/main/AndroidManifest.xml
index 750f052..ab19d5e 100644
--- a/wearable/wear/SpeedTracker/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/AndroidManifest.xml
@@ -24,7 +24,7 @@
 
     <uses-sdk
         android:minSdkVersion="20"
-        android:targetSdkVersion="20" />
+        android:targetSdkVersion="21" />
 
     <application
         android:allowBackup="true"
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/ui/SpeedPickerLayout.java b/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/ui/SpeedPickerLayout.java
index 9fd882d..5796c13 100644
--- a/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/ui/SpeedPickerLayout.java
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/ui/SpeedPickerLayout.java
@@ -30,13 +30,13 @@
  * A simple extension of the {@link android.widget.LinearLayout} to represent a single item in a
  * {@link android.support.wearable.view.WearableListView}.
  */
-public class SpeedPickerLayout extends LinearLayout implements WearableListView.Item {
+public class SpeedPickerLayout extends LinearLayout
+        implements WearableListView.OnCenterProximityListener {
 
     private final float mFadedTextAlpha;
     private final int mFadedCircleColor;
     private final int mChosenCircleColor;
     private ImageView mCircle;
-    private float mScale;
     private TextView mName;
 
     public SpeedPickerLayout(Context context) {
@@ -64,41 +64,16 @@
         mName = (TextView) findViewById(R.id.name);
     }
 
-    // Provide scaling values for WearableListView animations
     @Override
-    public float getProximityMinValue() {
-        return 1f;
-    }
-
-    @Override
-    public float getProximityMaxValue() {
-        return 1.6f;
-    }
-
-    @Override
-    public float getCurrentProximityValue() {
-        return mScale;
-    }
-
-    // Scale the icon for WearableListView animations
-    @Override
-    public void setScalingAnimatorValue(float scale) {
-        mScale = scale;
-        mCircle.setScaleX(scale);
-        mCircle.setScaleY(scale);
-    }
-
-    // Change color of the icon, remove fading from the text
-    @Override
-    public void onScaleUpStart() {
+    public void onCenterPosition(boolean animate) {
         mName.setAlpha(1f);
         ((GradientDrawable) mCircle.getDrawable()).setColor(mChosenCircleColor);
     }
 
-    // Change the color of the icon, fade the text
     @Override
-    public void onScaleDownStart() {
+    public void onNonCenterPosition(boolean animate) {
         ((GradientDrawable) mCircle.getDrawable()).setColor(mFadedCircleColor);
         mName.setAlpha(mFadedTextAlpha);
+
     }
 }
diff --git a/wearable/wear/SynchronizedNotifications/Application/src/main/AndroidManifest.xml b/wearable/wear/SynchronizedNotifications/Application/src/main/AndroidManifest.xml
index 9d7df72..1737c7d 100644
--- a/wearable/wear/SynchronizedNotifications/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/SynchronizedNotifications/Application/src/main/AndroidManifest.xml
@@ -23,7 +23,7 @@
     android:versionName="1.0">
 
     <uses-sdk android:minSdkVersion="18"
-        android:targetSdkVersion="20" />
+        android:targetSdkVersion="21" />
 
     <application android:allowBackup="true"
         android:label="@string/app_name"
diff --git a/wearable/wear/SynchronizedNotifications/CONTRIB.md b/wearable/wear/SynchronizedNotifications/CONTRIB.md
new file mode 100644
index 0000000..14a4fcf
--- /dev/null
+++ b/wearable/wear/SynchronizedNotifications/CONTRIB.md
@@ -0,0 +1,35 @@
+# How to become a contributor and submit your own code
+
+## Contributor License Agreements
+
+We'd love to accept your sample apps and patches! Before we can take them, we
+have to jump a couple of legal hurdles.
+
+Please fill out either the individual or corporate Contributor License Agreement (CLA).
+
+  * If you are an individual writing original source code and you're sure you
+    own the intellectual property, then you'll need to sign an [individual CLA]
+    (https://developers.google.com/open-source/cla/individual).
+  * If you work for a company that wants to allow you to contribute your work,
+    then you'll need to sign a [corporate CLA]
+    (https://developers.google.com/open-source/cla/corporate).
+
+Follow either of the two links above to access the appropriate CLA and
+instructions for how to sign and return it. Once we receive it, we'll be able to
+accept your pull requests.
+
+## Contributing A Patch
+
+1. Submit an issue describing your proposed change to the repo in question.
+1. The repo owner will respond to your issue promptly.
+1. If your proposed change is accepted, and you haven't already done so, sign a
+   Contributor License Agreement (see details above).
+1. Fork the desired repo, develop and test your code changes.
+1. Ensure that your code adheres to the existing style in the sample to which
+   you are contributing. Refer to the
+   [Android Code Style Guide]
+   (https://source.android.com/source/code-style.html) for the
+   recommended coding standards for this organization.
+1. Ensure that your code has an appropriate set of unit tests which all pass.
+1. Submit a pull request.
+
diff --git a/wearable/wear/SynchronizedNotifications/LICENSE b/wearable/wear/SynchronizedNotifications/LICENSE
new file mode 100644
index 0000000..1af981f
--- /dev/null
+++ b/wearable/wear/SynchronizedNotifications/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2014 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.
diff --git a/wearable/wear/SynchronizedNotifications/Shared/build.gradle b/wearable/wear/SynchronizedNotifications/Shared/build.gradle
deleted file mode 100644
index dda6f07..0000000
--- a/wearable/wear/SynchronizedNotifications/Shared/build.gradle
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-buildscript {
-    repositories {
-        mavenCentral()
-    }
-
-    dependencies {
-        classpath 'com.android.tools.build:gradle:0.12.+'
-    }
-}
-
-apply plugin: 'android-library'
-
-// The sample build uses multiple directories to
-// keep boilerplate and common code separate from
-// the main sample code.
-List<String> dirs = [
-    'main',     // main sample code; look here for the interesting stuff.
-    'common',   // components that are reused by multiple samples
-    'template'] // boilerplate code that is generated by the sample template process
-
-android {
-    compileSdkVersion "android-L"
-
-    buildToolsVersion '20'
-
-    sourceSets {
-        main {
-            dirs.each { dir ->
-                java.srcDirs "src/${dir}/java"
-                res.srcDirs "src/${dir}/res"
-            }
-        }
-
-    }
-}
diff --git a/wearable/wear/SynchronizedNotifications/Wearable/build.gradle b/wearable/wear/SynchronizedNotifications/Wearable/build.gradle
deleted file mode 100644
index 529a093..0000000
--- a/wearable/wear/SynchronizedNotifications/Wearable/build.gradle
+++ /dev/null
@@ -1,74 +0,0 @@
-
-
-
-buildscript {
-    repositories {
-        mavenCentral()
-    }
-
-    dependencies {
-        classpath 'com.android.tools.build:gradle:0.12.+'
-    }
-}
-
-apply plugin: 'com.android.application'
-
-
-
-dependencies {
-    compile 'com.google.android.gms:play-services:5.0.+@aar'
-    compile 'com.android.support:support-v13:20.0.+'
-    compile 'com.google.android.support:wearable:1.0.+'
-    compile project(':Shared')
-}
-
-// The sample build uses multiple directories to
-// keep boilerplate and common code separate from
-// the main sample code.
-List<String> dirs = [
-    'main',     // main sample code; look here for the interesting stuff.
-    'common',   // components that are reused by multiple samples
-    'template'] // boilerplate code that is generated by the sample template process
-
-android {
-    compileSdkVersion 'android-L'
-
-    buildToolsVersion '20'
-
-    buildTypes {
-        release {
-            runProguard false
-            proguardFiles getDefaultProguardFile('proguard-android.txt')
-        }
-    }
-    lintOptions {
-        abortOnError false
-    }
-    sourceSets {
-        main {
-            dirs.each { dir ->
-                java.srcDirs "src/${dir}/java"
-                res.srcDirs "src/${dir}/res"
-            }
-        }
-        androidTest.setRoot('tests')
-        androidTest.java.srcDirs = ['tests/src']
-
-    }
-}
-
-// BEGIN_EXCLUDE
-// Tasks below this line will be hidden from release output
-
-task preflight (dependsOn: parent.preflight) {
-    project.afterEvaluate {
-        // Inject a preflight task into each variant so we have a place to hook tasks
-        // that need to run before any of the android build tasks.
-        //
-        android.applicationVariants.each { variant ->
-            tasks.getByPath("prepare${variant.name.capitalize()}Dependencies").dependsOn preflight
-        }
-    }
-}
-
-// END_EXCLUDE
diff --git a/wearable/wear/SynchronizedNotifications/Wearable/src/main/AndroidManifest.xml b/wearable/wear/SynchronizedNotifications/Wearable/src/main/AndroidManifest.xml
index b8d5e85..f9b0d9c 100644
--- a/wearable/wear/SynchronizedNotifications/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/SynchronizedNotifications/Wearable/src/main/AndroidManifest.xml
@@ -20,7 +20,7 @@
     package="com.example.android.wearable.synchronizednotifications">
 
     <uses-sdk android:minSdkVersion="20"
-        android:targetSdkVersion="20" />
+        android:targetSdkVersion="21" />
 
     <uses-feature android:name="android.hardware.type.watch" />
 
diff --git a/wearable/wear/Timer/Application/src/main/AndroidManifest.xml b/wearable/wear/Timer/Application/src/main/AndroidManifest.xml
index 6b34b12..115e210 100644
--- a/wearable/wear/Timer/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/Timer/Application/src/main/AndroidManifest.xml
@@ -19,7 +19,7 @@
     package="com.example.android.wearable.timer">
 
     <uses-sdk android:minSdkVersion="18"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <application android:allowBackup="true"
         android:label="@string/app_name">
diff --git a/wearable/wear/Timer/Wearable/src/main/AndroidManifest.xml b/wearable/wear/Timer/Wearable/src/main/AndroidManifest.xml
index 9e27947..364fb5a 100644
--- a/wearable/wear/Timer/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/Timer/Wearable/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
         package="com.example.android.wearable.timer" >
 
     <uses-sdk android:minSdkVersion="20"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <uses-feature android:name="android.hardware.type.watch" />
 
diff --git a/wearable/wear/Timer/Wearable/src/main/java/com/example/android/wearable/timer/WearableListItemLayout.java b/wearable/wear/Timer/Wearable/src/main/java/com/example/android/wearable/timer/WearableListItemLayout.java
index 0bbc587..09591bf 100644
--- a/wearable/wear/Timer/Wearable/src/main/java/com/example/android/wearable/timer/WearableListItemLayout.java
+++ b/wearable/wear/Timer/Wearable/src/main/java/com/example/android/wearable/timer/WearableListItemLayout.java
@@ -24,12 +24,12 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-public class WearableListItemLayout extends LinearLayout implements WearableListView.Item {
+public class WearableListItemLayout extends LinearLayout
+        implements WearableListView.OnCenterProximityListener {
     private final float mFadedTextAlpha;
     private final int mFadedCircleColor;
     private final int mChosenCircleColor;
     private ImageView mCircle;
-    private float mScale;
     private TextView mName;
 
     public WearableListItemLayout(Context context) {
@@ -55,35 +55,13 @@
     }
 
     @Override
-    public float getProximityMinValue() {
-        return 1f;
-    }
-
-    @Override
-    public float getProximityMaxValue() {
-        return 1.6f;
-    }
-
-    @Override
-    public float getCurrentProximityValue() {
-        return mScale;
-    }
-
-    @Override
-    public void setScalingAnimatorValue(float scale) {
-        mScale = scale;
-        mCircle.setScaleX(scale);
-        mCircle.setScaleY(scale);
-    }
-
-    @Override
-    public void onScaleUpStart() {
+    public void onCenterPosition(boolean animate) {
         mName.setAlpha(1f);
         ((GradientDrawable) mCircle.getDrawable()).setColor(mChosenCircleColor);
     }
 
     @Override
-    public void onScaleDownStart() {
+    public void onNonCenterPosition(boolean animate) {
         ((GradientDrawable) mCircle.getDrawable()).setColor(mFadedCircleColor);
         mName.setAlpha(mFadedTextAlpha);
     }
diff --git a/wearable/wear/WatchFace/Application/.gitignore b/wearable/wear/WatchFace/Application/.gitignore
new file mode 100644
index 0000000..8fd2e1c
--- /dev/null
+++ b/wearable/wear/WatchFace/Application/.gitignore
@@ -0,0 +1,16 @@
+# Copyright 2014 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.
+src/template/
+src/common/
+build.gradle
diff --git a/wearable/wear/WatchFace/Application/proguard-project.txt b/wearable/wear/WatchFace/Application/proguard-project.txt
new file mode 100644
index 0000000..0d8f171
--- /dev/null
+++ b/wearable/wear/WatchFace/Application/proguard-project.txt
@@ -0,0 +1,20 @@
+ To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
diff --git a/wearable/wear/WatchFace/Application/src/main/AndroidManifest.xml b/wearable/wear/WatchFace/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..732e306
--- /dev/null
+++ b/wearable/wear/WatchFace/Application/src/main/AndroidManifest.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.example.android.wearable.watchface" >
+
+    <uses-sdk android:minSdkVersion="18"
+              android:targetSdkVersion="21" />
+
+    <!-- Permissions required by the wearable app -->
+    <uses-permission android:name="com.google.android.permission.PROVIDE_BACKGROUND" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.READ_CALENDAR" />
+
+    <!-- All intent-filters for config actions must include the categories
+        com.google.android.wearable.watchface.category.COMPANION_CONFIGURATION and
+        android.intent.category.DEFAULT. -->
+    <application
+            android:allowBackup="true"
+            android:icon="@drawable/ic_launcher"
+            android:label="@string/app_name"
+            android:theme="@style/AppTheme" >
+
+        <activity
+                android:name=".AnalogAndCardBoundsWatchFaceConfigActivity"
+                android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="com.example.android.wearable.watchface.CONFIG_ANALOG" />
+                <action android:name="com.example.android.wearable.watchface.CONFIG_CARD_BOUNDS" />
+                <category android:name="com.google.android.wearable.watchface.category.COMPANION_CONFIGURATION" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <activity
+                android:name=".DigitalWatchFaceCompanionConfigActivity"
+                android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="com.example.android.wearable.watchface.CONFIG_DIGITAL" />
+                <category android:name="com.google.android.wearable.watchface.category.COMPANION_CONFIGURATION" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <activity
+                android:name=".TiltWatchFaceConfigActivity"
+                android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="com.example.android.wearable.watchface.CONFIG_TILT" />
+                <category android:name="com.google.android.wearable.watchface.category.COMPANION_CONFIGURATION" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <meta-data
+                android:name="com.google.android.gms.version"
+                android:value="@integer/google_play_services_version" />
+
+    </application>
+
+</manifest>
diff --git a/wearable/wear/WatchFace/Application/src/main/java/com/example/android/wearable/watchface/AnalogAndCardBoundsWatchFaceConfigActivity.java b/wearable/wear/WatchFace/Application/src/main/java/com/example/android/wearable/watchface/AnalogAndCardBoundsWatchFaceConfigActivity.java
new file mode 100644
index 0000000..5943e6b
--- /dev/null
+++ b/wearable/wear/WatchFace/Application/src/main/java/com/example/android/wearable/watchface/AnalogAndCardBoundsWatchFaceConfigActivity.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 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.app.Activity;
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.support.wearable.companion.WatchFaceCompanion;
+import android.widget.TextView;
+
+public class AnalogAndCardBoundsWatchFaceConfigActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_analog_watch_face_config);
+
+        ComponentName name =
+                getIntent().getParcelableExtra(WatchFaceCompanion.EXTRA_WATCH_FACE_COMPONENT);
+        TextView label = (TextView) findViewById(R.id.label);
+        label.setText(label.getText() + " (" + name.getClassName() + ")");
+    }
+}
diff --git a/wearable/wear/WatchFace/Application/src/main/java/com/example/android/wearable/watchface/DigitalWatchFaceCompanionConfigActivity.java b/wearable/wear/WatchFace/Application/src/main/java/com/example/android/wearable/watchface/DigitalWatchFaceCompanionConfigActivity.java
new file mode 100644
index 0000000..b04f11e
--- /dev/null
+++ b/wearable/wear/WatchFace/Application/src/main/java/com/example/android/wearable/watchface/DigitalWatchFaceCompanionConfigActivity.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2014 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.app.Activity;
+import android.app.AlertDialog;
+import android.content.ComponentName;
+import android.content.DialogInterface;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.wearable.companion.WatchFaceCompanion;
+import android.util.Log;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.api.GoogleApiClient;
+import com.google.android.gms.common.api.ResultCallback;
+import com.google.android.gms.wearable.DataApi;
+import com.google.android.gms.wearable.DataItem;
+import com.google.android.gms.wearable.DataMap;
+import com.google.android.gms.wearable.DataMapItem;
+import com.google.android.gms.wearable.Wearable;
+
+/**
+ * The phone-side config activity for {@code DigitalWatchFaceService}. Like the watch-side config
+ * activity ({@code DigitalWatchFaceWearableConfigActivity}), allows for setting the background
+ * color. Additionally, enables setting the color for hour, minute and second digits.
+ */
+public class DigitalWatchFaceCompanionConfigActivity extends Activity
+        implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
+                ResultCallback<DataApi.DataItemResult> {
+    private static final String TAG = "DigitalWatchFaceConfig";
+
+    // TODO: use the shared constants (needs covering all the samples with Gradle build model)
+    private static final String KEY_BACKGROUND_COLOR = "BACKGROUND_COLOR";
+    private static final String KEY_HOURS_COLOR = "HOURS_COLOR";
+    private static final String KEY_MINUTES_COLOR = "MINUTES_COLOR";
+    private static final String KEY_SECONDS_COLOR = "SECONDS_COLOR";
+    private static final String PATH_WITH_FEATURE = "/watch_face_config/Digital";
+
+    private GoogleApiClient mGoogleApiClient;
+    private String mPeerId;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_digital_watch_face_config);
+
+        mPeerId = getIntent().getStringExtra(WatchFaceCompanion.EXTRA_PEER_ID);
+        mGoogleApiClient = new GoogleApiClient.Builder(this)
+                .addConnectionCallbacks(this)
+                .addOnConnectionFailedListener(this)
+                .addApi(Wearable.API)
+                .build();
+
+        ComponentName name = getIntent().getParcelableExtra(
+                WatchFaceCompanion.EXTRA_WATCH_FACE_COMPONENT);
+        TextView label = (TextView)findViewById(R.id.label);
+        label.setText(label.getText() + " (" + name.getClassName() + ")");
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        mGoogleApiClient.connect();
+    }
+
+    @Override
+    protected void onStop() {
+        if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
+            mGoogleApiClient.disconnect();
+        }
+        super.onStop();
+    }
+
+    @Override // GoogleApiClient.ConnectionCallbacks
+    public void onConnected(Bundle connectionHint) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "onConnected: " + connectionHint);
+        }
+
+        if (mPeerId != null) {
+            Uri.Builder builder = new Uri.Builder();
+            Uri uri = builder.scheme("wear").path(PATH_WITH_FEATURE).authority(mPeerId).build();
+            Wearable.DataApi.getDataItem(mGoogleApiClient, uri).setResultCallback(this);
+        } else {
+            displayNoConnectedDeviceDialog();
+        }
+    }
+
+    @Override // ResultCallback<DataApi.DataItemResult>
+    public void onResult(DataApi.DataItemResult dataItemResult) {
+        if (dataItemResult.getStatus().isSuccess() && dataItemResult.getDataItem() != null) {
+            DataItem configDataItem = dataItemResult.getDataItem();
+            DataMapItem dataMapItem = DataMapItem.fromDataItem(configDataItem);
+            DataMap config = dataMapItem.getDataMap();
+            setUpAllPickers(config);
+        } else {
+            // If DataItem with the current config can't be retrieved, select the default items on
+            // each picker.
+            setUpAllPickers(null);
+        }
+    }
+
+    @Override // GoogleApiClient.ConnectionCallbacks
+    public void onConnectionSuspended(int cause) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "onConnectionSuspended: " + cause);
+        }
+    }
+
+    @Override // GoogleApiClient.OnConnectionFailedListener
+    public void onConnectionFailed(ConnectionResult result) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "onConnectionFailed: " + result);
+        }
+    }
+
+    private void displayNoConnectedDeviceDialog() {
+        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        String messageText = getResources().getString(R.string.title_no_device_connected);
+        String okText = getResources().getString(R.string.ok_no_device_connected);
+        builder.setMessage(messageText)
+                .setCancelable(false)
+                .setPositiveButton(okText, new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int id) { }
+                });
+        AlertDialog alert = builder.create();
+        alert.show();
+    }
+
+    /**
+     * Sets up selected items for all pickers according to given {@code config} and sets up their
+     * item selection listeners.
+     *
+     * @param config the {@code DigitalWatchFaceService} config {@link DataMap}. If null, the
+     *         default items are selected.
+     */
+    private void setUpAllPickers(DataMap config) {
+        setUpColorPickerSelection(R.id.background, KEY_BACKGROUND_COLOR, config,
+                R.string.color_black);
+        setUpColorPickerSelection(R.id.hours, KEY_HOURS_COLOR, config, R.string.color_white);
+        setUpColorPickerSelection(R.id.minutes, KEY_MINUTES_COLOR, config, R.string.color_white);
+        setUpColorPickerSelection(R.id.seconds, KEY_SECONDS_COLOR, config, R.string.color_gray);
+
+        setUpColorPickerListener(R.id.background, KEY_BACKGROUND_COLOR);
+        setUpColorPickerListener(R.id.hours, KEY_HOURS_COLOR);
+        setUpColorPickerListener(R.id.minutes, KEY_MINUTES_COLOR);
+        setUpColorPickerListener(R.id.seconds, KEY_SECONDS_COLOR);
+    }
+
+    private void setUpColorPickerSelection(int spinnerId, final String configKey, DataMap config,
+            int defaultColorNameResId) {
+        String defaultColorName = getString(defaultColorNameResId);
+        int defaultColor = Color.parseColor(defaultColorName);
+        int color;
+        if (config != null) {
+            color = config.getInt(configKey, defaultColor);
+        } else {
+            color = defaultColor;
+        }
+        Spinner spinner = (Spinner) findViewById(spinnerId);
+        String[] colorNames = getResources().getStringArray(R.array.color_array);
+        for (int i = 0; i < colorNames.length; i++) {
+            if (Color.parseColor(colorNames[i]) == color) {
+                spinner.setSelection(i);
+                break;
+            }
+        }
+    }
+
+    private void setUpColorPickerListener(int spinnerId, final String configKey) {
+        Spinner spinner = (Spinner) findViewById(spinnerId);
+        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+            @Override
+            public void onItemSelected(AdapterView<?> adapterView, View view, int pos, long id) {
+                final String colorName = (String) adapterView.getItemAtPosition(pos);
+                sendConfigUpdateMessage(configKey, Color.parseColor(colorName));
+            }
+
+            @Override
+            public void onNothingSelected(AdapterView<?> adapterView) { }
+        });
+    }
+
+    private void sendConfigUpdateMessage(String configKey, int color) {
+        if (mPeerId != null) {
+            DataMap config = new DataMap();
+            config.putInt(configKey, color);
+            byte[] rawData = config.toByteArray();
+            Wearable.MessageApi.sendMessage(mGoogleApiClient, mPeerId, PATH_WITH_FEATURE, rawData);
+
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Sent watch face config message: " + configKey + " -> "
+                        + Integer.toHexString(color));
+            }
+        }
+    }
+}
diff --git a/wearable/wear/WatchFace/Application/src/main/java/com/example/android/wearable/watchface/TiltWatchFaceConfigActivity.java b/wearable/wear/WatchFace/Application/src/main/java/com/example/android/wearable/watchface/TiltWatchFaceConfigActivity.java
new file mode 100644
index 0000000..303e72e
--- /dev/null
+++ b/wearable/wear/WatchFace/Application/src/main/java/com/example/android/wearable/watchface/TiltWatchFaceConfigActivity.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 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.app.Activity;
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.support.wearable.companion.WatchFaceCompanion;
+import android.widget.TextView;
+
+public class TiltWatchFaceConfigActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_tilt_watch_face_config);
+
+        ComponentName name =
+                getIntent().getParcelableExtra(WatchFaceCompanion.EXTRA_WATCH_FACE_COMPONENT);
+        TextView label = (TextView)findViewById(R.id.label);
+        label.setText(label.getText() + " (" + name.getClassName() + ")");
+    }
+}
diff --git a/wearable/wear/WatchFace/Application/src/main/res/drawable-hdpi/ic_launcher.png b/wearable/wear/WatchFace/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100755
index 0000000..589f229
--- /dev/null
+++ b/wearable/wear/WatchFace/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/wearable/wear/WatchFace/Application/src/main/res/drawable-mdpi/ic_launcher.png b/wearable/wear/WatchFace/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100755
index 0000000..77dd571
--- /dev/null
+++ b/wearable/wear/WatchFace/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/wearable/wear/WatchFace/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/wearable/wear/WatchFace/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100755
index 0000000..fe34ebe
--- /dev/null
+++ b/wearable/wear/WatchFace/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/wearable/wear/WatchFace/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/wearable/wear/WatchFace/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100755
index 0000000..ab80bcd
--- /dev/null
+++ b/wearable/wear/WatchFace/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/wearable/wear/WatchFace/Application/src/main/res/layout/activity_analog_watch_face_config.xml b/wearable/wear/WatchFace/Application/src/main/res/layout/activity_analog_watch_face_config.xml
new file mode 100644
index 0000000..ec816c2
--- /dev/null
+++ b/wearable/wear/WatchFace/Application/src/main/res/layout/activity_analog_watch_face_config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/label"
+        android:text="@string/analog_config_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+</FrameLayout>
diff --git a/wearable/wear/WatchFace/Application/src/main/res/layout/activity_digital_watch_face_config.xml b/wearable/wear/WatchFace/Application/src/main/res/layout/activity_digital_watch_face_config.xml
new file mode 100644
index 0000000..204d523
--- /dev/null
+++ b/wearable/wear/WatchFace/Application/src/main/res/layout/activity_digital_watch_face_config.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/label"
+        android:text="@string/digital_config_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <TextView
+            android:text="@string/digital_config_background"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1" />
+        <Spinner
+            android:id="@+id/background"
+            android:entries="@array/color_array"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="3" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <TextView
+            android:text="@string/digital_config_hours"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1" />
+        <Spinner
+            android:id="@+id/hours"
+            android:entries="@array/color_array"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="3" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <TextView
+            android:text="@string/digital_config_minutes"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1" />
+        <Spinner
+            android:id="@+id/minutes"
+            android:entries="@array/color_array"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="3" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <TextView
+            android:text="@string/digital_config_seconds"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1" />
+        <Spinner
+            android:id="@+id/seconds"
+            android:entries="@array/color_array"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="3" />
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/wearable/wear/WatchFace/Application/src/main/res/layout/activity_tilt_watch_face_config.xml b/wearable/wear/WatchFace/Application/src/main/res/layout/activity_tilt_watch_face_config.xml
new file mode 100644
index 0000000..bda2d68
--- /dev/null
+++ b/wearable/wear/WatchFace/Application/src/main/res/layout/activity_tilt_watch_face_config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/label"
+        android:text="@string/tilt_config_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+</FrameLayout>
diff --git a/wearable/wear/WatchFace/Application/src/main/res/values/strings.xml b/wearable/wear/WatchFace/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..aacb108
--- /dev/null
+++ b/wearable/wear/WatchFace/Application/src/main/res/values/strings.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<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="digital_config_background">Background</string>
+    <string name="digital_config_hours">Hours</string>
+    <string name="digital_config_minutes">Minutes</string>
+    <string name="digital_config_seconds">Seconds</string>
+
+    <string name="title_no_device_connected">No wearable device is currently connected.</string>
+    <string name="ok_no_device_connected">OK</string>
+
+    <string name="color_black">Black</string>
+    <string name="color_blue">Blue</string>
+    <string name="color_gray">Gray</string>
+    <string name="color_green">Green</string>
+    <string name="color_navy">Navy</string>
+    <string name="color_red">Red</string>
+    <string name="color_white">White</string>
+
+    <string-array name="color_array">
+        <item>@string/color_black</item>
+        <item>@string/color_blue</item>
+        <item>@string/color_gray</item>
+        <item>@string/color_green</item>
+        <item>@string/color_navy</item>
+        <item>@string/color_red</item>
+        <item>@string/color_white</item>
+    </string-array>
+</resources>
diff --git a/wearable/wear/WatchFace/CONTRIB.md b/wearable/wear/WatchFace/CONTRIB.md
new file mode 100644
index 0000000..14a4fcf
--- /dev/null
+++ b/wearable/wear/WatchFace/CONTRIB.md
@@ -0,0 +1,35 @@
+# How to become a contributor and submit your own code
+
+## Contributor License Agreements
+
+We'd love to accept your sample apps and patches! Before we can take them, we
+have to jump a couple of legal hurdles.
+
+Please fill out either the individual or corporate Contributor License Agreement (CLA).
+
+  * If you are an individual writing original source code and you're sure you
+    own the intellectual property, then you'll need to sign an [individual CLA]
+    (https://developers.google.com/open-source/cla/individual).
+  * If you work for a company that wants to allow you to contribute your work,
+    then you'll need to sign a [corporate CLA]
+    (https://developers.google.com/open-source/cla/corporate).
+
+Follow either of the two links above to access the appropriate CLA and
+instructions for how to sign and return it. Once we receive it, we'll be able to
+accept your pull requests.
+
+## Contributing A Patch
+
+1. Submit an issue describing your proposed change to the repo in question.
+1. The repo owner will respond to your issue promptly.
+1. If your proposed change is accepted, and you haven't already done so, sign a
+   Contributor License Agreement (see details above).
+1. Fork the desired repo, develop and test your code changes.
+1. Ensure that your code adheres to the existing style in the sample to which
+   you are contributing. Refer to the
+   [Android Code Style Guide]
+   (https://source.android.com/source/code-style.html) for the
+   recommended coding standards for this organization.
+1. Ensure that your code has an appropriate set of unit tests which all pass.
+1. Submit a pull request.
+
diff --git a/wearable/wear/WatchFace/LICENSE b/wearable/wear/WatchFace/LICENSE
new file mode 100644
index 0000000..1af981f
--- /dev/null
+++ b/wearable/wear/WatchFace/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2014 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.
diff --git a/wearable/wear/WatchFace/Wearable/.gitignore b/wearable/wear/WatchFace/Wearable/.gitignore
new file mode 100644
index 0000000..8fd2e1c
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/.gitignore
@@ -0,0 +1,16 @@
+# Copyright 2014 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.
+src/template/
+src/common/
+build.gradle
diff --git a/wearable/wear/WatchFace/Wearable/src/main/AndroidManifest.xml b/wearable/wear/WatchFace/Wearable/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..6e0aac2
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/AndroidManifest.xml
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.example.android.wearable.watchface" >
+
+    <uses-sdk android:minSdkVersion="21"
+        android:targetSdkVersion="21" />
+
+    <uses-feature android:name="android.hardware.type.watch" />
+
+    <!-- Required to act as a custom watch face. -->
+    <uses-permission android:name="com.google.android.permission.PROVIDE_BACKGROUND" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+    <!-- Calendar permission used by CalendarWatchFaceService -->
+    <uses-permission android:name="android.permission.READ_CALENDAR" />
+
+    <application
+            android:allowBackup="true"
+            android:icon="@drawable/ic_launcher"
+            android:label="@string/app_name" >
+
+        <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.companionConfigurationAction"
+                    android:value="com.example.android.wearable.watchface.CONFIG_ANALOG" />
+            <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=".SweepWatchFaceService"
+                android:label="@string/sweep_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" />
+            <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=".TiltWatchFaceService"
+                android:label="@string/tilt_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_tilt" />
+            <meta-data
+                    android:name="com.google.android.wearable.watchface.companionConfigurationAction"
+                    android:value="com.example.android.wearable.watchface.CONFIG_TILT" />
+
+            <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=".CardBoundsWatchFaceService"
+                android:label="@string/card_bounds_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_card_bounds" />
+            <meta-data
+                    android:name="com.google.android.wearable.watchface.companionConfigurationAction"
+                    android:value="com.example.android.wearable.watchface.CONFIG_CARD_BOUNDS" />
+            <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"
+                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_digital" />
+            <meta-data
+                    android:name="com.google.android.wearable.watchface.companionConfigurationAction"
+                    android:value="com.example.android.wearable.watchface.CONFIG_DIGITAL" />
+            <meta-data
+                    android:name="com.google.android.wearable.watchface.wearableConfigurationAction"
+                    android:value="com.example.android.wearable.watchface.CONFIG_DIGITAL" />
+            <intent-filter>
+                <action android:name="android.service.wallpaper.WallpaperService" />
+                <category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
+            </intent-filter>
+        </service>
+
+        <!-- All intent-filters for config actions must include the categories
+            com.google.android.wearable.watchface.category.WEARABLE_CONFIGURATION
+            and android.intent.category.DEFAULT. -->
+
+        <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>
+
+        <service
+                android:name=".CalendarWatchFaceService"
+                android:label="@string/calendar_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_calendar" />
+            <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=".DigitalWatchFaceConfigListenerService">
+            <intent-filter>
+                <action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
+            </intent-filter>
+        </service>
+
+        <meta-data
+                android:name="com.google.android.gms.version"
+                android:value="@integer/google_play_services_version" />
+
+    </application>
+
+</manifest>
diff --git a/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/AnalogWatchFaceService.java b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/AnalogWatchFaceService.java
new file mode 100644
index 0000000..19c8d2b
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/AnalogWatchFaceService.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2014 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.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+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.wearable.watchface.CanvasWatchFaceService;
+import android.support.wearable.watchface.WatchFaceService;
+import android.support.wearable.watchface.WatchFaceStyle;
+import android.text.format.Time;
+import android.util.Log;
+import android.view.SurfaceHolder;
+
+import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Sample analog watch face with a ticking second hand. In ambient mode, the second hand isn't
+ * shown. On devices with low-bit ambient mode, the hands are drawn without anti-aliasing in ambient
+ * mode. The watch face is drawn with less contrast in mute mode.
+ *
+ * {@link SweepWatchFaceService} is similar but has a sweep second hand.
+ */
+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.
+     */
+    private static final long INTERACTIVE_UPDATE_RATE_MS = TimeUnit.SECONDS.toMillis(1);
+
+    @Override
+    public Engine onCreateEngine() {
+        return new Engine();
+    }
+
+    private class Engine extends CanvasWatchFaceService.Engine {
+        static final int MSG_UPDATE_TIME = 0;
+
+        Paint mHourPaint;
+        Paint mMinutePaint;
+        Paint mSecondPaint;
+        Paint mTickPaint;
+        boolean mMute;
+        Time mTime;
+
+        /** 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 (isVisible()) {
+                            long timeMs = System.currentTimeMillis();
+                            long delayMs = INTERACTIVE_UPDATE_RATE_MS
+                                    - (timeMs % INTERACTIVE_UPDATE_RATE_MS);
+                            mUpdateTimeHandler.sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs);
+                        }
+                        break;
+                }
+            }
+        };
+
+        final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                mTime.clear(intent.getStringExtra("time-zone"));
+                mTime.setToNow();
+            }
+        };
+        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) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onCreate");
+            }
+            super.onCreate(holder);
+
+            setWatchFaceStyle(new WatchFaceStyle.Builder(AnalogWatchFaceService.this)
+                    .setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
+                    .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
+                    .setShowSystemUiTime(false)
+                    .build());
+
+            Resources resources = AnalogWatchFaceService.this.getResources();
+            Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg);
+            mBackgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();
+
+            mHourPaint = new Paint();
+            mHourPaint.setARGB(255, 200, 200, 200);
+            mHourPaint.setStrokeWidth(5.f);
+            mHourPaint.setAntiAlias(true);
+            mHourPaint.setStrokeCap(Paint.Cap.ROUND);
+
+            mMinutePaint = new Paint();
+            mMinutePaint.setARGB(255, 200, 200, 200);
+            mMinutePaint.setStrokeWidth(3.f);
+            mMinutePaint.setAntiAlias(true);
+            mMinutePaint.setStrokeCap(Paint.Cap.ROUND);
+
+            mSecondPaint = new Paint();
+            mSecondPaint.setARGB(255, 255, 0, 0);
+            mSecondPaint.setStrokeWidth(2.f);
+            mSecondPaint.setAntiAlias(true);
+            mSecondPaint.setStrokeCap(Paint.Cap.ROUND);
+
+            mTickPaint = new Paint();
+            mTickPaint.setARGB(100, 255, 255, 255);
+            mTickPaint.setStrokeWidth(2.f);
+            mTickPaint.setAntiAlias(true);
+
+            mTime = new Time();
+        }
+
+        @Override
+        public void onDestroy() {
+            mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
+            super.onDestroy();
+        }
+
+        @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);
+            }
+        }
+
+        @Override
+        public void onTimeTick() {
+            super.onTimeTick();
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onTimeTick: ambient = " + isInAmbientMode());
+            }
+            invalidate();
+        }
+
+        @Override
+        public void onAmbientModeChanged(boolean inAmbientMode) {
+            super.onAmbientModeChanged(inAmbientMode);
+            if (mLowBitAmbient) {
+                boolean antiAlias = !inAmbientMode;
+                mHourPaint.setAntiAlias(antiAlias);
+                mMinutePaint.setAntiAlias(antiAlias);
+                mSecondPaint.setAntiAlias(antiAlias);
+                mTickPaint.setAntiAlias(antiAlias);
+            }
+            invalidate();
+        }
+
+        @Override
+        public void onInterruptionFilterChanged(int interruptionFilter) {
+            super.onInterruptionFilterChanged(interruptionFilter);
+            boolean inMuteMode = (interruptionFilter == WatchFaceService.INTERRUPTION_FILTER_NONE);
+            if (mMute != inMuteMode) {
+                mMute = inMuteMode;
+                mHourPaint.setAlpha(inMuteMode ? 100 : 255);
+                mMinutePaint.setAlpha(inMuteMode ? 100 : 255);
+                mSecondPaint.setAlpha(inMuteMode ? 80 : 255);
+                invalidate();
+            }
+        }
+
+        @Override
+        public void onDraw(Canvas canvas) {
+            mTime.setToNow();
+
+            int width = canvas.getWidth();
+            int height = canvas.getHeight();
+
+            // 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;
+
+            // Draw the ticks.
+            float innerTickRadius = centerX - 10;
+            float outerTickRadius = centerX;
+            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);
+            }
+
+            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;
+
+            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);
+            }
+
+            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);
+        }
+
+        @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();
+
+                mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME);
+            } else {
+                mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
+                unregisterReceiver();
+            }
+        }
+
+        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);
+        }
+    }
+}
diff --git a/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/CalendarWatchFaceService.java b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/CalendarWatchFaceService.java
new file mode 100644
index 0000000..929651d
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/CalendarWatchFaceService.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2014 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.ContentUris;
+import android.database.Cursor;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.Message;
+import android.support.wearable.provider.WearableCalendarContract;
+import android.support.wearable.watchface.CanvasWatchFaceService;
+import android.support.wearable.watchface.WatchFaceStyle;
+import android.text.DynamicLayout;
+import android.text.Editable;
+import android.text.Html;
+import android.text.Layout;
+import android.text.SpannableStringBuilder;
+import android.text.TextPaint;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.view.SurfaceHolder;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Proof of concept sample watch face that demonstrates how a watch face can load calendar data.
+ */
+public class CalendarWatchFaceService extends CanvasWatchFaceService {
+    private static final String TAG = "CalendarWatchFace";
+
+    /**
+     * How long to wait after loading meetings before loading them again. Meetings are only loaded
+     * in interactive mode.
+     */
+    private static final long LOAD_MEETINGS_DELAY_MS = TimeUnit.MINUTES.toMillis(1);
+
+    @Override
+    public Engine onCreateEngine() {
+        return new Engine();
+    }
+
+    private class Engine extends CanvasWatchFaceService.Engine {
+
+        static final int BACKGROUND_COLOR = Color.BLACK;
+        static final int FOREGROUND_COLOR = Color.WHITE;
+        static final int TEXT_SIZE = 25;
+        static final int MSG_LOAD_MEETINGS = 0;
+
+        /** Editable string containing the text to draw with the number of meetings in bold. */
+        final Editable mEditable = new SpannableStringBuilder();
+
+        /** Width specified when {@link #mLayout} was created. */
+        int mLayoutWidth;
+
+        /** Layout to wrap {@link #mEditable} onto multiple lines. */
+        DynamicLayout mLayout;
+
+        /** Paint used to draw text. */
+        final TextPaint mTextPaint = new TextPaint();
+
+        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;
+                }
+            }
+        };
+
+        @Override
+        public void onCreate(SurfaceHolder holder) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onCreate");
+            }
+            super.onCreate(holder);
+            setWatchFaceStyle(new WatchFaceStyle.Builder(CalendarWatchFaceService.this)
+                    .setCardPeekMode(WatchFaceStyle.PEEK_MODE_VARIABLE)
+                    .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
+                    .setShowSystemUiTime(false)
+                    .build());
+
+            mTextPaint.setColor(FOREGROUND_COLOR);
+            mTextPaint.setTextSize(TEXT_SIZE);
+        }
+
+        @Override
+        public void onDestroy() {
+            mLoadMeetingsHandler.removeMessages(MSG_LOAD_MEETINGS);
+            cancelLoadMeetingTask();
+            super.onDestroy();
+        }
+
+        @Override
+        public void onDraw(Canvas canvas) {
+            // Create or update mLayout if necessary.
+            if (mLayout == null || mLayoutWidth != canvas.getWidth()) {
+                mLayoutWidth = canvas.getWidth();
+                mLayout = new DynamicLayout(mEditable, mTextPaint, mLayoutWidth,
+                        Layout.Alignment.ALIGN_NORMAL, 1 /* spacingMult */, 0 /* spacingAdd */,
+                        false /* includePad */);
+            }
+
+            // Update the contents of mEditable.
+            mEditable.clear();
+            mEditable.append(Html.fromHtml(getResources().getQuantityString(
+                    R.plurals.calendar_meetings, mNumMeetings, mNumMeetings)));
+
+            // Draw the text on a solid background.
+            canvas.drawColor(BACKGROUND_COLOR);
+            mLayout.draw(canvas);
+        }
+
+        @Override
+        public void onVisibilityChanged(boolean visible) {
+            super.onVisibilityChanged(visible);
+            if (visible) {
+                mLoadMeetingsHandler.sendEmptyMessage(MSG_LOAD_MEETINGS);
+            } else {
+                mLoadMeetingsHandler.removeMessages(MSG_LOAD_MEETINGS);
+                cancelLoadMeetingTask();
+            }
+        }
+
+        private void onMeetingsLoaded(Integer result) {
+            if (result != null) {
+                mNumMeetings = result;
+                invalidate();
+            }
+            if (isVisible()) {
+                mLoadMeetingsHandler.sendEmptyMessageDelayed(
+                        MSG_LOAD_MEETINGS, LOAD_MEETINGS_DELAY_MS);
+            }
+        }
+
+        private void cancelLoadMeetingTask() {
+            if (mLoadMeetingsTask != null) {
+                mLoadMeetingsTask.cancel(true);
+            }
+        }
+
+        /**
+         * Asynchronous task to load the meetings from the content provider and report the number of
+         * meetings back via {@link #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) {
+                onMeetingsLoaded(result);
+            }
+        }
+    }
+}
diff --git a/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/CardBoundsWatchFaceService.java b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/CardBoundsWatchFaceService.java
new file mode 100644
index 0000000..c0d4437
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/CardBoundsWatchFaceService.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2014 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.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.support.wearable.watchface.CanvasWatchFaceService;
+import android.support.wearable.watchface.WatchFaceStyle;
+import android.util.Log;
+import android.view.SurfaceHolder;
+
+/**
+ * Proof of concept sample watch face that demonstrates how a watch face can detect where the peek
+ * card is. This watch face draws a border around the area where the peeking card is.
+ */
+public class CardBoundsWatchFaceService extends CanvasWatchFaceService {
+
+    private static final String TAG = "CardBoundsWatchFace";
+
+    @Override
+    public Engine onCreateEngine() {
+        return new Engine();
+    }
+
+    private class Engine extends CanvasWatchFaceService.Engine {
+
+        static final int BORDER_WIDTH_PX = 5;
+
+        final Rect mCardBounds = new Rect();
+        final Paint mPaint = new Paint();
+
+        @Override
+        public void onCreate(SurfaceHolder holder) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onCreate");
+            }
+            super.onCreate(holder);
+            setWatchFaceStyle(new WatchFaceStyle.Builder(CardBoundsWatchFaceService.this)
+                    .setCardPeekMode(WatchFaceStyle.PEEK_MODE_VARIABLE)
+                    .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
+                    .setShowSystemUiTime(true)
+                    .setPeekOpacityMode(WatchFaceStyle.PEEK_OPACITY_MODE_TRANSLUCENT)
+                    .build());
+        }
+
+        @Override
+        public void onAmbientModeChanged(boolean inAmbientMode) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onAmbientModeChanged: " + inAmbientMode);
+            }
+            super.onAmbientModeChanged(inAmbientMode);
+            invalidate();
+        }
+
+        @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 onDraw(Canvas canvas) {
+            // Clear screen.
+            canvas.drawColor(isInAmbientMode() ? Color.BLACK : Color.BLUE);
+
+            // Draw border around card in interactive mode.
+            if (!isInAmbientMode()) {
+                mPaint.setColor(Color.MAGENTA);
+                canvas.drawRect(mCardBounds.left - BORDER_WIDTH_PX,
+                        mCardBounds.top - BORDER_WIDTH_PX,
+                        mCardBounds.right + BORDER_WIDTH_PX,
+                        mCardBounds.bottom + BORDER_WIDTH_PX, mPaint);
+            }
+
+            // Fill area under card.
+            mPaint.setColor(isInAmbientMode() ? Color.RED : Color.GREEN);
+            canvas.drawRect(mCardBounds, mPaint);
+        }
+    }
+}
diff --git a/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/DigitalWatchFaceConfigListenerService.java b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/DigitalWatchFaceConfigListenerService.java
new file mode 100644
index 0000000..725c51a
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/DigitalWatchFaceConfigListenerService.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 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.os.Bundle;
+import android.util.Log;
+
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.api.GoogleApiClient;
+import com.google.android.gms.wearable.DataMap;
+import com.google.android.gms.wearable.MessageEvent;
+import com.google.android.gms.wearable.Wearable;
+import com.google.android.gms.wearable.WearableListenerService;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A {@link WearableListenerService} listening for {@link DigitalWatchFaceService} config messages
+ * and updating the config {@link com.google.android.gms.wearable.DataItem} accordingly.
+ */
+public class DigitalWatchFaceConfigListenerService extends WearableListenerService
+        implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
+    private static final String TAG = "DigitalListenerService";
+
+    private GoogleApiClient mGoogleApiClient;
+
+    @Override // WearableListenerService
+    public void onMessageReceived(MessageEvent messageEvent) {
+        if (!messageEvent.getPath().equals(DigitalWatchFaceUtil.PATH_WITH_FEATURE)) {
+            return;
+        }
+        byte[] rawData = messageEvent.getData();
+        // It's allowed that the message carries only some of the keys used in the config DataItem
+        // and skips the ones that we don't want to change.
+        DataMap configKeysToOverwrite = DataMap.fromByteArray(rawData);
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "Received watch face config message: " + configKeysToOverwrite);
+        }
+
+        if (mGoogleApiClient == null) {
+            mGoogleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this)
+                    .addOnConnectionFailedListener(this).addApi(Wearable.API).build();
+        }
+        if (!mGoogleApiClient.isConnected()) {
+            ConnectionResult connectionResult =
+                    mGoogleApiClient.blockingConnect(30, TimeUnit.SECONDS);
+
+            if (!connectionResult.isSuccess()) {
+                Log.e(TAG, "Failed to connect to GoogleApiClient.");
+                return;
+            }
+        }
+
+        DigitalWatchFaceUtil.overwriteKeysInConfigDataMap(mGoogleApiClient, configKeysToOverwrite);
+    }
+
+    @Override // GoogleApiClient.ConnectionCallbacks
+    public void onConnected(Bundle connectionHint) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "onConnected: " + connectionHint);
+        }
+    }
+
+    @Override  // GoogleApiClient.ConnectionCallbacks
+    public void onConnectionSuspended(int cause) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "onConnectionSuspended: " + cause);
+        }
+    }
+
+    @Override  // GoogleApiClient.OnConnectionFailedListener
+    public void onConnectionFailed(ConnectionResult result) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "onConnectionFailed: " + result);
+        }
+    }
+}
diff --git a/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/DigitalWatchFaceService.java b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/DigitalWatchFaceService.java
new file mode 100644
index 0000000..7620d1a
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/DigitalWatchFaceService.java
@@ -0,0 +1,574 @@
+/*
+ * Copyright (C) 2014 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.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.support.wearable.watchface.CanvasWatchFaceService;
+import android.support.wearable.watchface.WatchFaceService;
+import android.support.wearable.watchface.WatchFaceStyle;
+import android.text.format.Time;
+import android.util.Log;
+import android.view.SurfaceHolder;
+import android.view.WindowInsets;
+
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.api.GoogleApiClient;
+import com.google.android.gms.wearable.DataApi;
+import com.google.android.gms.wearable.DataEvent;
+import com.google.android.gms.wearable.DataEventBuffer;
+import com.google.android.gms.wearable.DataItem;
+import com.google.android.gms.wearable.DataMap;
+import com.google.android.gms.wearable.DataMapItem;
+import com.google.android.gms.wearable.Wearable;
+
+import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Sample digital watch face with blinking colons and seconds. In ambient mode, the seconds are
+ * replaced with an AM/PM indicator and the colons don't blink. On devices with low-bit ambient
+ * mode, the text is drawn without anti-aliasing in ambient mode. On devices which require burn-in
+ * protection, the hours are drawn in normal rather than bold. The time is drawn with less contrast
+ * and without seconds in mute mode.
+ */
+public class DigitalWatchFaceService extends CanvasWatchFaceService {
+    private static final String TAG = "DigitalWatchFaceService";
+
+    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);
+
+    /**
+     * Update rate in milliseconds for normal (not ambient and not mute) mode. We update twice
+     * a second to blink the colons.
+     */
+    private static final long NORMAL_UPDATE_RATE_MS = 500;
+
+    /**
+     * Update rate in milliseconds for mute mode. We update every minute, like in ambient mode.
+     */
+    private static final long MUTE_UPDATE_RATE_MS = TimeUnit.MINUTES.toMillis(1);
+
+    @Override
+    public Engine onCreateEngine() {
+        return new Engine();
+    }
+
+    private class Engine extends CanvasWatchFaceService.Engine implements DataApi.DataListener,
+            GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
+        static final String COLON_STRING = ":";
+
+        /** Alpha value for drawing time when in mute mode. */
+        static final int MUTE_ALPHA = 100;
+
+        /** Alpha value for drawing time when not in mute mode. */
+        static final int NORMAL_ALPHA = 255;
+
+        static final int MSG_UPDATE_TIME = 0;
+
+        /** How often {@link #mUpdateTimeHandler} ticks in milliseconds. */
+        long mInteractiveUpdateRateMs = NORMAL_UPDATE_RATE_MS;
+
+        /** Handler to update the time periodically 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 (isVisible()) {
+                            long timeMs = System.currentTimeMillis();
+                            long delayMs = mInteractiveUpdateRateMs
+                                    - (timeMs % mInteractiveUpdateRateMs);
+                            mUpdateTimeHandler.sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs);
+                        }
+                        break;
+                }
+            }
+        };
+
+        GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(DigitalWatchFaceService.this)
+                .addConnectionCallbacks(this)
+                .addOnConnectionFailedListener(this)
+                .addApi(Wearable.API)
+                .build();
+
+        final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                mTime.clear(intent.getStringExtra("time-zone"));
+                mTime.setToNow();
+            }
+        };
+        boolean mRegisteredTimeZoneReceiver = false;
+
+        Paint mBackgroundPaint;
+        Paint mHourPaint;
+        Paint mMinutePaint;
+        Paint mSecondPaint;
+        Paint mAmPmPaint;
+        Paint mColonPaint;
+        float mColonWidth;
+        boolean mMute;
+        Time mTime;
+        boolean mShouldDrawColons;
+        float mXOffset;
+        float mYOffset;
+        String mAmString;
+        String mPmString;
+        int mInteractiveBackgroundColor =
+                DigitalWatchFaceUtil.COLOR_VALUE_DEFAULT_AND_AMBIENT_BACKGROUND;
+        int mInteractiveHourDigitsColor =
+                DigitalWatchFaceUtil.COLOR_VALUE_DEFAULT_AND_AMBIENT_HOUR_DIGITS;
+        int mInteractiveMinuteDigitsColor =
+                DigitalWatchFaceUtil.COLOR_VALUE_DEFAULT_AND_AMBIENT_MINUTE_DIGITS;
+        int mInteractiveSecondDigitsColor =
+                DigitalWatchFaceUtil.COLOR_VALUE_DEFAULT_AND_AMBIENT_SECOND_DIGITS;
+
+        /**
+         * Whether the display supports fewer bits for each color in ambient mode. When true, we
+         * disable anti-aliasing in ambient mode.
+         */
+        boolean mLowBitAmbient;
+
+        @Override
+        public void onCreate(SurfaceHolder holder) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onCreate");
+            }
+            super.onCreate(holder);
+
+            setWatchFaceStyle(new WatchFaceStyle.Builder(DigitalWatchFaceService.this)
+                    .setCardPeekMode(WatchFaceStyle.PEEK_MODE_VARIABLE)
+                    .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
+                    .setShowSystemUiTime(false)
+                    .build());
+            Resources resources = DigitalWatchFaceService.this.getResources();
+            mYOffset = resources.getDimension(R.dimen.digital_y_offset);
+            mAmString = resources.getString(R.string.digital_am);
+            mPmString = resources.getString(R.string.digital_pm);
+
+            mBackgroundPaint = new Paint();
+            mBackgroundPaint.setColor(mInteractiveBackgroundColor);
+            mHourPaint = createTextPaint(mInteractiveHourDigitsColor, BOLD_TYPEFACE);
+            mMinutePaint = createTextPaint(mInteractiveMinuteDigitsColor);
+            mSecondPaint = createTextPaint(mInteractiveSecondDigitsColor);
+            mAmPmPaint = createTextPaint(resources.getColor(R.color.digital_am_pm));
+            mColonPaint = createTextPaint(resources.getColor(R.color.digital_colons));
+
+            mTime = new Time();
+        }
+
+        @Override
+        public void onDestroy() {
+            mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
+            super.onDestroy();
+        }
+
+        private Paint createTextPaint(int defaultInteractiveColor) {
+            return createTextPaint(defaultInteractiveColor, NORMAL_TYPEFACE);
+        }
+
+        private Paint createTextPaint(int defaultInteractiveColor, Typeface typeface) {
+            Paint paint = new Paint();
+            paint.setColor(defaultInteractiveColor);
+            paint.setTypeface(typeface);
+            paint.setAntiAlias(true);
+            return paint;
+        }
+
+        @Override
+        public void onVisibilityChanged(boolean visible) {
+            super.onVisibilityChanged(visible);
+
+            if (visible) {
+                mGoogleApiClient.connect();
+
+                registerReceiver();
+
+                // Update time zone in case it changed while we weren't visible.
+                mTime.clear(TimeZone.getDefault().getID());
+                mTime.setToNow();
+
+                mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME);
+            } else {
+                mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
+
+                unregisterReceiver();
+
+                if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
+                    Wearable.DataApi.removeListener(mGoogleApiClient, this);
+                    mGoogleApiClient.disconnect();
+                }
+            }
+        }
+
+        private void registerReceiver() {
+            if (mRegisteredTimeZoneReceiver) {
+                return;
+            }
+            mRegisteredTimeZoneReceiver = true;
+            IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
+            DigitalWatchFaceService.this.registerReceiver(mTimeZoneReceiver, filter);
+        }
+
+        private void unregisterReceiver() {
+            if (!mRegisteredTimeZoneReceiver) {
+                return;
+            }
+            mRegisteredTimeZoneReceiver = false;
+            DigitalWatchFaceService.this.unregisterReceiver(mTimeZoneReceiver);
+        }
+
+        @Override
+        public void onApplyWindowInsets(WindowInsets insets) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onApplyWindowInsets: " + (insets.isRound() ? "round" : "square"));
+            }
+            super.onApplyWindowInsets(insets);
+
+            // Load resources that have alternate values for round watches.
+            Resources resources = DigitalWatchFaceService.this.getResources();
+            boolean isRound = insets.isRound();
+            mXOffset = resources.getDimension(isRound
+                    ? R.dimen.digital_x_offset_round : R.dimen.digital_x_offset);
+            float textSize = resources.getDimension(isRound
+                    ? R.dimen.digital_text_size_round : R.dimen.digital_text_size);
+            float amPmSize = resources.getDimension(isRound
+                    ? R.dimen.digital_am_pm_size_round : R.dimen.digital_am_pm_size);
+
+            mHourPaint.setTextSize(textSize);
+            mMinutePaint.setTextSize(textSize);
+            mSecondPaint.setTextSize(textSize);
+            mAmPmPaint.setTextSize(amPmSize);
+            mColonPaint.setTextSize(textSize);
+
+            mColonWidth = mColonPaint.measureText(COLON_STRING);
+        }
+
+        @Override
+        public void onPropertiesChanged(Bundle properties) {
+            super.onPropertiesChanged(properties);
+
+            boolean burnInProtection = properties.getBoolean(PROPERTY_BURN_IN_PROTECTION, false);
+            mHourPaint.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 onTimeTick() {
+            super.onTimeTick();
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onTimeTick: ambient = " + isInAmbientMode());
+            }
+            invalidate();
+        }
+
+        @Override
+        public void onAmbientModeChanged(boolean inAmbientMode) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onAmbientModeChanged: " + inAmbientMode);
+            }
+            super.onAmbientModeChanged(inAmbientMode);
+            adjustPaintColorToCurrentMode(mBackgroundPaint, mInteractiveBackgroundColor,
+                    DigitalWatchFaceUtil.COLOR_VALUE_DEFAULT_AND_AMBIENT_BACKGROUND);
+            adjustPaintColorToCurrentMode(mHourPaint, mInteractiveHourDigitsColor,
+                    DigitalWatchFaceUtil.COLOR_VALUE_DEFAULT_AND_AMBIENT_HOUR_DIGITS);
+            adjustPaintColorToCurrentMode(mMinutePaint, mInteractiveMinuteDigitsColor,
+                    DigitalWatchFaceUtil.COLOR_VALUE_DEFAULT_AND_AMBIENT_MINUTE_DIGITS);
+            // Actually, the seconds are not rendered in the ambient mode, so we could pass just
+            // any value as ambientColor here.
+            adjustPaintColorToCurrentMode(mSecondPaint, mInteractiveSecondDigitsColor,
+                    DigitalWatchFaceUtil.COLOR_VALUE_DEFAULT_AND_AMBIENT_SECOND_DIGITS);
+
+            if (mLowBitAmbient) {
+                boolean antiAlias = !inAmbientMode;
+                mHourPaint.setAntiAlias(antiAlias);
+                mMinutePaint.setAntiAlias(antiAlias);
+                mSecondPaint.setAntiAlias(antiAlias);
+                mAmPmPaint.setAntiAlias(antiAlias);
+                mColonPaint.setAntiAlias(antiAlias);
+            }
+            invalidate();
+        }
+
+        private void adjustPaintColorToCurrentMode(Paint paint, int interactiveColor,
+                int ambientColor) {
+            paint.setColor(isInAmbientMode() ? ambientColor : interactiveColor);
+        }
+
+        @Override
+        public void onInterruptionFilterChanged(int interruptionFilter) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onInterruptionFilterChanged: " + interruptionFilter);
+            }
+            super.onInterruptionFilterChanged(interruptionFilter);
+
+            boolean inMuteMode = interruptionFilter == WatchFaceService.INTERRUPTION_FILTER_NONE;
+            // We only need to update once a minute in mute mode.
+            setInteractiveUpdateRateMs(inMuteMode ? MUTE_UPDATE_RATE_MS : NORMAL_UPDATE_RATE_MS);
+
+            if (mMute != inMuteMode) {
+                mMute = inMuteMode;
+                int alpha = inMuteMode ? MUTE_ALPHA : NORMAL_ALPHA;
+                mHourPaint.setAlpha(alpha);
+                mMinutePaint.setAlpha(alpha);
+                mColonPaint.setAlpha(alpha);
+                mAmPmPaint.setAlpha(alpha);
+                invalidate();
+            }
+        }
+
+        public void setInteractiveUpdateRateMs(long updateRateMs) {
+            if (updateRateMs == mInteractiveUpdateRateMs) {
+                return;
+            }
+            mInteractiveUpdateRateMs = updateRateMs;
+            if (isVisible()) {
+                mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
+                mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME);
+            }
+        }
+
+        private void updatePaintIfInteractive(Paint paint, int interactiveColor) {
+            if (!isInAmbientMode() && paint != null) {
+                paint.setColor(interactiveColor);
+            }
+        }
+
+        private void setInteractiveBackgroundColor(int color) {
+            mInteractiveBackgroundColor = color;
+            updatePaintIfInteractive(mBackgroundPaint, color);
+        }
+
+        private void setInteractiveHourDigitsColor(int color) {
+            mInteractiveHourDigitsColor = color;
+            updatePaintIfInteractive(mHourPaint, color);
+        }
+
+        private void setInteractiveMinuteDigitsColor(int color) {
+            mInteractiveMinuteDigitsColor = color;
+            updatePaintIfInteractive(mMinutePaint, color);
+        }
+
+        private void setInteractiveSecondDigitsColor(int color) {
+            mInteractiveSecondDigitsColor = color;
+            updatePaintIfInteractive(mSecondPaint, color);
+        }
+
+        private String formatTwoDigitNumber(int hour) {
+            return String.format("%02d", hour);
+        }
+
+        private int convertTo12Hour(int hour) {
+            int result = hour % 12;
+            return (result == 0) ? 12 : result;
+        }
+
+        private String getAmPmString(int hour) {
+            return (hour < 12) ? mAmString : mPmString;
+        }
+
+        @Override
+        public void onDraw(Canvas canvas) {
+            mTime.setToNow();
+
+            // Show colons for the first half of each second so the colons blink on when the time
+            // updates.
+            mShouldDrawColons = (System.currentTimeMillis() % 1000) < 500;
+
+            // Draw the background.
+            canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mBackgroundPaint);
+
+            // Draw the hours.
+            float x = mXOffset;
+            String hourString = String.valueOf(convertTo12Hour(mTime.hour));
+            canvas.drawText(hourString, x, mYOffset, mHourPaint);
+            x += mHourPaint.measureText(hourString);
+
+            // In ambient and mute modes, always draw the first colon. Otherwise, draw the
+            // first colon for the first half of each second.
+            if (isInAmbientMode() || mMute || mShouldDrawColons) {
+                canvas.drawText(COLON_STRING, x, mYOffset, mColonPaint);
+            }
+            x += mColonWidth;
+
+            // Draw the minutes.
+            String minuteString = formatTwoDigitNumber(mTime.minute);
+            canvas.drawText(minuteString, x, mYOffset, mMinutePaint);
+            x += mMinutePaint.measureText(minuteString);
+
+            // In ambient and mute modes, draw AM/PM. Otherwise, draw a second blinking
+            // colon followed by the seconds.
+            if (isInAmbientMode() || mMute) {
+                x += mColonWidth;
+                canvas.drawText(getAmPmString(mTime.hour), x, mYOffset, mAmPmPaint);
+            } else {
+                if (mShouldDrawColons) {
+                    canvas.drawText(COLON_STRING, x, mYOffset, mColonPaint);
+                }
+                x += mColonWidth;
+                canvas.drawText(formatTwoDigitNumber(mTime.second), x, mYOffset,
+                        mSecondPaint);
+            }
+        }
+
+        private void updateConfigDataItemAndUiOnStartup() {
+            DigitalWatchFaceUtil.fetchConfigDataMap(mGoogleApiClient,
+                    new DigitalWatchFaceUtil.FetchConfigDataMapCallback() {
+                        @Override
+                        public void onConfigDataMapFetched(DataMap startupConfig) {
+                            // If the DataItem hasn't been created yet or some keys are missing,
+                            // use the default values.
+                            setDefaultValuesForMissingConfigKeys(startupConfig);
+                            DigitalWatchFaceUtil.putConfigDataItem(mGoogleApiClient, startupConfig);
+
+                            updateUiForConfigDataMap(startupConfig);
+                        }
+                    }
+            );
+        }
+
+        private void setDefaultValuesForMissingConfigKeys(DataMap config) {
+            addIntKeyIfMissing(config, DigitalWatchFaceUtil.KEY_BACKGROUND_COLOR,
+                    DigitalWatchFaceUtil.COLOR_VALUE_DEFAULT_AND_AMBIENT_BACKGROUND);
+            addIntKeyIfMissing(config, DigitalWatchFaceUtil.KEY_HOURS_COLOR,
+                    DigitalWatchFaceUtil.COLOR_VALUE_DEFAULT_AND_AMBIENT_HOUR_DIGITS);
+            addIntKeyIfMissing(config, DigitalWatchFaceUtil.KEY_MINUTES_COLOR,
+                    DigitalWatchFaceUtil.COLOR_VALUE_DEFAULT_AND_AMBIENT_MINUTE_DIGITS);
+            addIntKeyIfMissing(config, DigitalWatchFaceUtil.KEY_SECONDS_COLOR,
+                    DigitalWatchFaceUtil.COLOR_VALUE_DEFAULT_AND_AMBIENT_SECOND_DIGITS);
+        }
+
+        private void addIntKeyIfMissing(DataMap config, String key, int color) {
+            if (!config.containsKey(key)) {
+                config.putInt(key, color);
+            }
+        }
+
+        @Override // DataApi.DataListener
+        public void onDataChanged(DataEventBuffer dataEvents) {
+            try {
+                for (DataEvent dataEvent : dataEvents) {
+                    if (dataEvent.getType() != DataEvent.TYPE_CHANGED) {
+                        continue;
+                    }
+
+                    DataItem dataItem = dataEvent.getDataItem();
+                    if (!dataItem.getUri().getPath().equals(
+                            DigitalWatchFaceUtil.PATH_WITH_FEATURE)) {
+                        continue;
+                    }
+
+                    DataMapItem dataMapItem = DataMapItem.fromDataItem(dataItem);
+                    DataMap config = dataMapItem.getDataMap();
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG, "Config DataItem updated:" + config);
+                    }
+                    updateUiForConfigDataMap(config);
+                }
+            } finally {
+                dataEvents.close();
+            }
+        }
+
+        private void updateUiForConfigDataMap(final DataMap config) {
+            boolean uiUpdated = false;
+            for (String configKey : config.keySet()) {
+                if (!config.containsKey(configKey)) {
+                    continue;
+                }
+                int color = config.getInt(configKey);
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    Log.d(TAG, "Found watch face config key: " + configKey + " -> "
+                            + Integer.toHexString(color));
+                }
+                if (updateUiForKey(configKey, color)) {
+                    uiUpdated = true;
+                }
+            }
+            if (uiUpdated) {
+                invalidate();
+            }
+        }
+
+        /**
+         * Updates the color of a UI item according to the given {@code configKey}. Does nothing if
+         * {@code configKey} isn't recognized.
+         *
+         * @return whether UI has been updated
+         */
+        private boolean updateUiForKey(String configKey, int color) {
+            if (configKey.equals(DigitalWatchFaceUtil.KEY_BACKGROUND_COLOR)) {
+                setInteractiveBackgroundColor(color);
+            } else if (configKey.equals(DigitalWatchFaceUtil.KEY_HOURS_COLOR)) {
+                setInteractiveHourDigitsColor(color);
+            } else if (configKey.equals(DigitalWatchFaceUtil.KEY_MINUTES_COLOR)) {
+                setInteractiveMinuteDigitsColor(color);
+            } else if (configKey.equals(DigitalWatchFaceUtil.KEY_SECONDS_COLOR)) {
+                setInteractiveSecondDigitsColor(color);
+            } else {
+                Log.w(TAG, "Ignoring unknown config key: " + configKey);
+                return false;
+            }
+            return true;
+        }
+
+        @Override  // GoogleApiClient.ConnectionCallbacks
+        public void onConnected(Bundle connectionHint) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onConnected: " + connectionHint);
+            }
+            Wearable.DataApi.addListener(mGoogleApiClient, Engine.this);
+            updateConfigDataItemAndUiOnStartup();
+        }
+
+        @Override  // GoogleApiClient.ConnectionCallbacks
+        public void onConnectionSuspended(int cause) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onConnectionSuspended: " + cause);
+            }
+        }
+
+        @Override  // GoogleApiClient.OnConnectionFailedListener
+        public void onConnectionFailed(ConnectionResult result) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onConnectionFailed: " + result);
+            }
+        }
+    }
+}
diff --git a/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/DigitalWatchFaceUtil.java b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/DigitalWatchFaceUtil.java
new file mode 100644
index 0000000..1c4af70
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/DigitalWatchFaceUtil.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2014 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.graphics.Color;
+import android.net.Uri;
+import android.util.Log;
+
+import com.google.android.gms.common.api.GoogleApiClient;
+import com.google.android.gms.common.api.ResultCallback;
+import com.google.android.gms.wearable.DataApi;
+import com.google.android.gms.wearable.DataItem;
+import com.google.android.gms.wearable.DataMap;
+import com.google.android.gms.wearable.DataMapItem;
+import com.google.android.gms.wearable.NodeApi;
+import com.google.android.gms.wearable.PutDataMapRequest;
+import com.google.android.gms.wearable.Wearable;
+
+public final class DigitalWatchFaceUtil {
+    private static final String TAG = "DigitalWatchFaceUtil";
+
+    /**
+     * The {@link DataMap} key for {@link DigitalWatchFaceService} background color name.
+     * The color name must be a {@link String} recognized by {@link Color#parseColor}.
+     */
+    public static final String KEY_BACKGROUND_COLOR = "BACKGROUND_COLOR";
+
+    /**
+     * The {@link DataMap} key for {@link DigitalWatchFaceService} hour digits color name.
+     * The color name must be a {@link String} recognized by {@link Color#parseColor}.
+     */
+    public static final String KEY_HOURS_COLOR = "HOURS_COLOR";
+
+    /**
+     * The {@link DataMap} key for {@link DigitalWatchFaceService} minute digits color name.
+     * The color name must be a {@link String} recognized by {@link Color#parseColor}.
+     */
+    public static final String KEY_MINUTES_COLOR = "MINUTES_COLOR";
+
+    /**
+     * The {@link DataMap} key for {@link DigitalWatchFaceService} second digits color name.
+     * The color name must be a {@link String} recognized by {@link Color#parseColor}.
+     */
+    public static final String KEY_SECONDS_COLOR = "SECONDS_COLOR";
+
+    /**
+     * The path for the {@link DataItem} containing {@link DigitalWatchFaceService} configuration.
+     */
+    public static final String PATH_WITH_FEATURE = "/watch_face_config/Digital";
+
+    /**
+     * Name of the default interactive mode background color and the ambient mode background color.
+     */
+    public static final String COLOR_NAME_DEFAULT_AND_AMBIENT_BACKGROUND = "Black";
+    public static final int COLOR_VALUE_DEFAULT_AND_AMBIENT_BACKGROUND =
+            parseColor(COLOR_NAME_DEFAULT_AND_AMBIENT_BACKGROUND);
+
+    /**
+     * Name of the default interactive mode hour digits color and the ambient mode hour digits
+     * color.
+     */
+    public static final String COLOR_NAME_DEFAULT_AND_AMBIENT_HOUR_DIGITS = "White";
+    public static final int COLOR_VALUE_DEFAULT_AND_AMBIENT_HOUR_DIGITS =
+            parseColor(COLOR_NAME_DEFAULT_AND_AMBIENT_HOUR_DIGITS);
+
+    /**
+     * Name of the default interactive mode minute digits color and the ambient mode minute digits
+     * color.
+     */
+    public static final String COLOR_NAME_DEFAULT_AND_AMBIENT_MINUTE_DIGITS = "White";
+    public static final int COLOR_VALUE_DEFAULT_AND_AMBIENT_MINUTE_DIGITS =
+            parseColor(COLOR_NAME_DEFAULT_AND_AMBIENT_MINUTE_DIGITS);
+
+    /**
+     * Name of the default interactive mode second digits color and the ambient mode second digits
+     * color.
+     */
+    public static final String COLOR_NAME_DEFAULT_AND_AMBIENT_SECOND_DIGITS = "Gray";
+    public static final int COLOR_VALUE_DEFAULT_AND_AMBIENT_SECOND_DIGITS =
+            parseColor(COLOR_NAME_DEFAULT_AND_AMBIENT_SECOND_DIGITS);
+
+    /**
+     * Callback interface to perform an action with the current config {@link DataMap} for
+     * {@link DigitalWatchFaceService}.
+     */
+    public interface FetchConfigDataMapCallback {
+        /**
+         * Callback invoked with the current config {@link DataMap} for
+         * {@link DigitalWatchFaceService}.
+         */
+        void onConfigDataMapFetched(DataMap config);
+    }
+
+    private static int parseColor(String colorName) {
+        return Color.parseColor(colorName.toLowerCase());
+    }
+
+    /**
+     * Asynchronously fetches the current config {@link DataMap} for {@link DigitalWatchFaceService}
+     * and passes it to the given callback.
+     * <p>
+     * If the current config {@link DataItem} doesn't exist, it isn't created and the callback
+     * receives an empty DataMap.
+     */
+    public static void fetchConfigDataMap(final GoogleApiClient client,
+            final FetchConfigDataMapCallback callback) {
+        Wearable.NodeApi.getLocalNode(client).setResultCallback(
+                new ResultCallback<NodeApi.GetLocalNodeResult>() {
+                    @Override
+                    public void onResult(NodeApi.GetLocalNodeResult getLocalNodeResult) {
+                        String localNode = getLocalNodeResult.getNode().getId();
+                        Uri uri = new Uri.Builder()
+                                .scheme("wear")
+                                .path(DigitalWatchFaceUtil.PATH_WITH_FEATURE)
+                                .authority(localNode)
+                                .build();
+                        Wearable.DataApi.getDataItem(client, uri)
+                                .setResultCallback(new DataItemResultCallback(callback));
+                    }
+                }
+        );
+    }
+
+    /**
+     * Overwrites (or sets, if not present) the keys in the current config {@link DataItem} with
+     * the ones appearing in the given {@link DataMap}. If the config DataItem doesn't exist,
+     * it's created.
+     * <p>
+     * It is allowed that only some of the keys used in the config DataItem appear in
+     * {@code configKeysToOverwrite}. The rest of the keys remains unmodified in this case.
+     */
+    public static void overwriteKeysInConfigDataMap(final GoogleApiClient googleApiClient,
+            final DataMap configKeysToOverwrite) {
+
+        DigitalWatchFaceUtil.fetchConfigDataMap(googleApiClient,
+                new FetchConfigDataMapCallback() {
+                    @Override
+                    public void onConfigDataMapFetched(DataMap currentConfig) {
+                        DataMap overwrittenConfig = new DataMap();
+                        overwrittenConfig.putAll(currentConfig);
+                        overwrittenConfig.putAll(configKeysToOverwrite);
+                        DigitalWatchFaceUtil.putConfigDataItem(googleApiClient, overwrittenConfig);
+                    }
+                }
+        );
+    }
+
+    /**
+     * Overwrites the current config {@link DataItem}'s {@link DataMap} with {@code newConfig}.
+     * If the config DataItem doesn't exist, it's created.
+     */
+    public static void putConfigDataItem(GoogleApiClient googleApiClient, DataMap newConfig) {
+        PutDataMapRequest putDataMapRequest = PutDataMapRequest.create(PATH_WITH_FEATURE);
+        DataMap configToPut = putDataMapRequest.getDataMap();
+        configToPut.putAll(newConfig);
+        Wearable.DataApi.putDataItem(googleApiClient, putDataMapRequest.asPutDataRequest())
+                .setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
+                    @Override
+                    public void onResult(DataApi.DataItemResult dataItemResult) {
+                        if (Log.isLoggable(TAG, Log.DEBUG)) {
+                            Log.d(TAG, "putDataItem result status: " + dataItemResult.getStatus());
+                        }
+                    }
+                });
+    }
+
+    private static class DataItemResultCallback implements ResultCallback<DataApi.DataItemResult> {
+
+        private final FetchConfigDataMapCallback mCallback;
+
+        public DataItemResultCallback(FetchConfigDataMapCallback callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        public void onResult(DataApi.DataItemResult dataItemResult) {
+            if (dataItemResult.getStatus().isSuccess()) {
+                if (dataItemResult.getDataItem() != null) {
+                    DataItem configDataItem = dataItemResult.getDataItem();
+                    DataMapItem dataMapItem = DataMapItem.fromDataItem(configDataItem);
+                    DataMap config = dataMapItem.getDataMap();
+                    mCallback.onConfigDataMapFetched(config);
+                } else {
+                    mCallback.onConfigDataMapFetched(new DataMap());
+                }
+            }
+        }
+    }
+
+    private DigitalWatchFaceUtil() { }
+}
diff --git a/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/DigitalWatchFaceWearableConfigActivity.java b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/DigitalWatchFaceWearableConfigActivity.java
new file mode 100644
index 0000000..a2e5251
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/DigitalWatchFaceWearableConfigActivity.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2014 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.app.Activity;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.wearable.view.WearableListView;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.api.GoogleApiClient;
+import com.google.android.gms.wearable.DataMap;
+import com.google.android.gms.wearable.Wearable;
+
+/**
+ * The watch-side config activity for {@link DigitalWatchFaceService}, which allows for setting the
+ * background color.
+ */
+public class DigitalWatchFaceWearableConfigActivity extends Activity
+        implements WearableListView.ClickListener {
+    private static final String TAG = "DigitalWatchFaceConfig";
+
+    private GoogleApiClient mGoogleApiClient;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_digital_config);
+
+        WearableListView listView = (WearableListView) findViewById(R.id.color_picker);
+
+        listView.setHasFixedSize(true);
+        listView.setClickListener(this);
+
+        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
+        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
+        listView.setLayoutManager(layoutManager);
+
+        String[] colors = getResources().getStringArray(R.array.color_array);
+        listView.setAdapter(new ColorListAdapter(colors));
+
+        mGoogleApiClient = new GoogleApiClient.Builder(this)
+                .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
+                    @Override
+                    public void onConnected(Bundle connectionHint) {
+                        if (Log.isLoggable(TAG, Log.DEBUG)) {
+                            Log.d(TAG, "onConnected: " + connectionHint);
+                        }
+                    }
+
+                    @Override
+                    public void onConnectionSuspended(int cause) {
+                        if (Log.isLoggable(TAG, Log.DEBUG)) {
+                            Log.d(TAG, "onConnectionSuspended: " + cause);
+                        }
+                    }
+                })
+                .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
+                    @Override
+                    public void onConnectionFailed(ConnectionResult result) {
+                        if (Log.isLoggable(TAG, Log.DEBUG)) {
+                            Log.d(TAG, "onConnectionFailed: " + result);
+                        }
+                    }
+                })
+                .addApi(Wearable.API)
+                .build();
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        mGoogleApiClient.connect();
+    }
+
+    @Override
+    protected void onStop() {
+        if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
+            mGoogleApiClient.disconnect();
+        }
+        super.onStop();
+    }
+
+    @Override // WearableListView.ClickListener
+    public void onClick(WearableListView.ViewHolder viewHolder) {
+        ColorItemViewHolder colorItemViewHolder = (ColorItemViewHolder) viewHolder;
+        String colorName = colorItemViewHolder.mLabel.getText().toString();
+        updateConfigDataItem(Color.parseColor(colorName));
+        finish();
+    }
+
+    private void updateConfigDataItem(final int backgroundColor) {
+        DataMap configKeysToOverwrite = new DataMap();
+        configKeysToOverwrite.putInt(DigitalWatchFaceUtil.KEY_BACKGROUND_COLOR,
+                backgroundColor);
+        DigitalWatchFaceUtil.overwriteKeysInConfigDataMap(mGoogleApiClient, configKeysToOverwrite);
+    }
+
+    @Override // WearableListView.ClickListener
+    public void onTopEmptyRegionClick() { }
+
+    private class ColorListAdapter extends RecyclerView.Adapter<ColorItemViewHolder> {
+
+        private final String[] mColors;
+
+        public ColorListAdapter(String[] colors) {
+            mColors = colors;
+        }
+
+        @Override
+        public ColorItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+            View root = LayoutInflater.from(parent.getContext())
+                    .inflate(R.layout.color_picker_item, parent, false /* attachToRoot */);
+            TextView label = (TextView) root.findViewById(R.id.label);
+            return new ColorItemViewHolder(root, label);
+        }
+
+        @Override
+        public void onBindViewHolder(ColorItemViewHolder holder, int position) {
+            String colorName = mColors[position];
+            holder.mLabel.setText(colorName);
+
+            RecyclerView.LayoutParams layoutParams =
+                    new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                            ViewGroup.LayoutParams.WRAP_CONTENT);
+            int colorPickerItemMargin = (int) getResources()
+                    .getDimension(R.dimen.digital_config_color_picker_item_margin);
+            // Add margins to first and last item to make it possible for user to tap on them.
+            if (position == 0) {
+                layoutParams.setMargins(0, colorPickerItemMargin, 0, 0);
+            } else if (position == mColors.length - 1) {
+                layoutParams.setMargins(0, 0, 0, colorPickerItemMargin);
+            } else {
+                layoutParams.setMargins(0, 0, 0, 0);
+            }
+            holder.itemView.setLayoutParams(layoutParams);
+        }
+
+        @Override
+        public int getItemCount() {
+            return mColors.length;
+        }
+    }
+
+    private static class ColorItemViewHolder extends WearableListView.ViewHolder {
+        private final TextView mLabel;
+
+        public ColorItemViewHolder(View root, TextView label) {
+            super(root);
+            this.mLabel = label;
+        }
+    }
+}
diff --git a/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/Gles2ColoredTriangleList.java b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/Gles2ColoredTriangleList.java
new file mode 100644
index 0000000..2441c65
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/Gles2ColoredTriangleList.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2014 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 java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+import android.opengl.GLES20;
+import android.opengl.GLU;
+import android.opengl.GLUtils;
+import android.util.Log;
+
+/**
+ * A list of triangles drawn in a single solid color using OpenGL ES 2.0.
+ */
+public class Gles2ColoredTriangleList {
+    private static final String TAG = "GlColoredTriangleList";
+
+    /** Whether to check for GL errors. This is slow, so not appropriate for production builds. */
+    private static final boolean CHECK_GL_ERRORS = false;
+
+    /** Number of coordinates per vertex in this array: one for each of x, y, and z. */
+    private static final int COORDS_PER_VERTEX = 3;
+
+    /** Number of bytes to store a float in GL. */
+    public static final int BYTES_PER_FLOAT = 4;
+
+    /** Number of bytes per vertex. */
+    private static final int VERTEX_STRIDE = COORDS_PER_VERTEX * BYTES_PER_FLOAT;
+
+    /** Triangles have three vertices. */
+    private static final int VERTICE_PER_TRIANGLE = 3;
+
+    /**
+     * Number of components in an OpenGL color. The components are:<ol>
+     * <li>red
+     * <li>green
+     * <li>blue
+     * <li>alpha
+     * </ol>
+     */
+    private static final int NUM_COLOR_COMPONENTS = 4;
+
+    /** Shaders to render this triangle list. */
+    private final Program mProgram;
+
+    /** The VBO containing the vertex coordinates. */
+    private final FloatBuffer mVertexBuffer;
+
+    /**
+     * Color of this triangle list represented as an array of floats in the range [0, 1] in RGBA
+     * order.
+     */
+    private final float mColor[];
+
+    /** Number of coordinates in this triangle list. */
+    private final int mNumCoords;
+
+    /**
+     * Creates a Gles2ColoredTriangleList to draw a triangle list with the given vertices and color.
+     *
+     * @param program program for drawing triangles
+     * @param triangleCoords flat array of 3D coordinates of triangle vertices in counterclockwise
+     *                       order
+     * @param color color in RGBA order, each in the range [0, 1]
+     */
+    public Gles2ColoredTriangleList(Program program, float[] triangleCoords, float[] color) {
+        if (triangleCoords.length % (VERTICE_PER_TRIANGLE * COORDS_PER_VERTEX) != 0) {
+            throw new IllegalArgumentException("must be multiple"
+                    + " of VERTICE_PER_TRIANGLE * COORDS_PER_VERTEX coordinates");
+        }
+        if (color.length != NUM_COLOR_COMPONENTS) {
+            throw new IllegalArgumentException("wrong number of color components");
+        }
+        mProgram = program;
+        mColor = color;
+
+        ByteBuffer bb = ByteBuffer.allocateDirect(triangleCoords.length * BYTES_PER_FLOAT);
+
+        // Use the device hardware's native byte order.
+        bb.order(ByteOrder.nativeOrder());
+
+        // Create a FloatBuffer that wraps the ByteBuffer.
+        mVertexBuffer = bb.asFloatBuffer();
+
+        // Add the coordinates to the FloatBuffer.
+        mVertexBuffer.put(triangleCoords);
+
+        // Go back to the start for reading.
+        mVertexBuffer.position(0);
+
+        mNumCoords = triangleCoords.length / COORDS_PER_VERTEX;
+    }
+
+    /**
+     * Draws this triangle list using OpenGL commands.
+     *
+     * @param mvpMatrix the Model View Project matrix to draw this triangle list
+     */
+    public void draw(float[] mvpMatrix) {
+        // Pass the MVP matrix, vertex data, and color to OpenGL.
+        mProgram.bind(mvpMatrix, mVertexBuffer, mColor);
+
+        // Draw the triangle list.
+        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mNumCoords);
+        if (CHECK_GL_ERRORS) checkGlError("glDrawArrays");
+    }
+
+    /**
+     * Checks if any of the GL calls since the last time this method was called set an error
+     * condition. Call this method immediately after calling a GL method. Pass the name of the GL
+     * operation. For example:
+     *
+     * <pre>
+     * mColorHandle = GLES20.glGetUniformLocation(mProgram, "uColor");
+     * MyGLRenderer.checkGlError("glGetUniformLocation");</pre>
+     *
+     * If the operation is not successful, the check throws an exception.
+     *
+     * <p><em>Note</em> This is quite slow so it's best to use it sparingly in production builds.
+     *
+     * @param glOperation name of the OpenGL call to check
+     */
+    private static void checkGlError(String glOperation) {
+        int error = GLES20.glGetError();
+        if (error != GLES20.GL_NO_ERROR) {
+            String errorString = GLU.gluErrorString(error);
+            if (errorString == null) {
+                errorString = GLUtils.getEGLErrorString(error);
+            }
+            String message = glOperation + " caused GL error 0x" + Integer.toHexString(error) +
+                    ": " + errorString;
+            Log.e(TAG, message);
+            throw new RuntimeException(message);
+        }
+    }
+
+    /**
+     * Compiles an OpenGL shader.
+     *
+     * @param type {@link GLES20#GL_VERTEX_SHADER} or {@link GLES20#GL_FRAGMENT_SHADER}
+     * @param shaderCode string containing the shader source code
+     * @return ID for the shader
+     */
+    private static int loadShader(int type, String shaderCode){
+        // Create a vertex or fragment shader.
+        int shader = GLES20.glCreateShader(type);
+        if (CHECK_GL_ERRORS) checkGlError("glCreateShader");
+        if (shader == 0) {
+            throw new IllegalStateException("glCreateShader failed");
+        }
+
+        // Add the source code to the shader and compile it.
+        GLES20.glShaderSource(shader, shaderCode);
+        if (CHECK_GL_ERRORS) checkGlError("glShaderSource");
+        GLES20.glCompileShader(shader);
+        if (CHECK_GL_ERRORS) checkGlError("glCompileShader");
+
+        return shader;
+    }
+
+    /** OpenGL shaders for drawing solid colored triangle lists. */
+    public static class Program {
+        /** Trivial vertex shader that transforms the input vertex by the MVP matrix. */
+        private static final String VERTEX_SHADER_CODE = "" +
+                "uniform mat4 uMvpMatrix;\n" +
+                "attribute vec4 aPosition;\n" +
+                "void main() {\n" +
+                "    gl_Position = uMvpMatrix * aPosition;\n" +
+                "}\n";
+
+        /** Trivial fragment shader that draws with a fixed color. */
+        private static final String FRAGMENT_SHADER_CODE = "" +
+                "precision mediump float;\n" +
+                "uniform vec4 uColor;\n" +
+                "void main() {\n" +
+                "    gl_FragColor = uColor;\n" +
+                "}\n";
+
+        /** ID OpenGL uses to identify this program. */
+        private final int mProgramId;
+
+        /** Handle for uMvpMatrix uniform in vertex shader. */
+        private final int mMvpMatrixHandle;
+
+        /** Handle for aPosition attribute in vertex shader. */
+        private final int mPositionHandle;
+
+        /** Handle for uColor uniform in fragment shader. */
+        private final int mColorHandle;
+
+        /**
+         * Creates a program to draw triangle lists. For optimal drawing efficiency, one program
+         * should be used for all triangle lists being drawn.
+         */
+        public Program() {
+            // Prepare shaders.
+            int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER_CODE);
+            int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER_CODE);
+
+            // Create empty OpenGL Program.
+            mProgramId = GLES20.glCreateProgram();
+            if (CHECK_GL_ERRORS) checkGlError("glCreateProgram");
+            if (mProgramId == 0) {
+                throw new IllegalStateException("glCreateProgram failed");
+            }
+
+            // Add the shaders to the program.
+            GLES20.glAttachShader(mProgramId, vertexShader);
+            if (CHECK_GL_ERRORS) checkGlError("glAttachShader");
+            GLES20.glAttachShader(mProgramId, fragmentShader);
+            if (CHECK_GL_ERRORS) checkGlError("glAttachShader");
+
+            // Link the program so it can be executed.
+            GLES20.glLinkProgram(mProgramId);
+            if (CHECK_GL_ERRORS) checkGlError("glLinkProgram");
+
+            // Get a handle to the uMvpMatrix uniform in the vertex shader.
+            mMvpMatrixHandle = GLES20.glGetUniformLocation(mProgramId, "uMvpMatrix");
+            if (CHECK_GL_ERRORS) checkGlError("glGetUniformLocation");
+
+            // Get a handle to the vertex shader's aPosition attribute.
+            mPositionHandle = GLES20.glGetAttribLocation(mProgramId, "aPosition");
+            if (CHECK_GL_ERRORS) checkGlError("glGetAttribLocation");
+
+            // Enable vertex array (VBO).
+            GLES20.glEnableVertexAttribArray(mPositionHandle);
+            if (CHECK_GL_ERRORS) checkGlError("glEnableVertexAttribArray");
+
+            // Get a handle to fragment shader's uColor uniform.
+            mColorHandle = GLES20.glGetUniformLocation(mProgramId, "uColor");
+            if (CHECK_GL_ERRORS) checkGlError("glGetUniformLocation");
+        }
+
+        /**
+         * Tells OpenGL to use this program. Call this method before drawing a sequence of
+         * triangle lists.
+         */
+        public void use() {
+            GLES20.glUseProgram(mProgramId);
+            if (CHECK_GL_ERRORS) checkGlError("glUseProgram");
+        }
+
+        /** Sends the given MVP matrix, vertex data, and color to OpenGL. */
+        public void bind(float[] mvpMatrix, FloatBuffer vertexBuffer, float[] color) {
+            // Pass the MVP matrix to OpenGL.
+            GLES20.glUniformMatrix4fv(mMvpMatrixHandle, 1 /* count */, false /* transpose */,
+                    mvpMatrix, 0 /* offset */);
+            if (CHECK_GL_ERRORS) checkGlError("glUniformMatrix4fv");
+
+            // Pass the VBO with the triangle list's vertices to OpenGL.
+            GLES20.glEnableVertexAttribArray(mPositionHandle);
+            if (CHECK_GL_ERRORS) checkGlError("glEnableVertexAttribArray");
+            GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT,
+                    false /* normalized */, VERTEX_STRIDE, vertexBuffer);
+            if (CHECK_GL_ERRORS) checkGlError("glVertexAttribPointer");
+
+            // Pass the triangle list's color to OpenGL.
+            GLES20.glUniform4fv(mColorHandle, 1 /* count */, color, 0 /* offset */);
+            if (CHECK_GL_ERRORS) checkGlError("glUniform4fv");
+        }
+    }
+}
diff --git a/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/SweepWatchFaceService.java b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/SweepWatchFaceService.java
new file mode 100644
index 0000000..5fc738b
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/SweepWatchFaceService.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2014 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.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.wearable.watchface.CanvasWatchFaceService;
+import android.support.wearable.watchface.WatchFaceService;
+import android.support.wearable.watchface.WatchFaceStyle;
+import android.text.format.Time;
+import android.util.Log;
+import android.view.SurfaceHolder;
+
+import java.util.TimeZone;
+
+/**
+ * Sample analog watch face with a sweep second hand. In ambient mode, the second hand isn't shown.
+ * On devices with low-bit ambient mode, the hands are drawn without anti-aliasing in ambient mode.
+ * The watch face is drawn with less contrast in mute mode.
+ *
+ * {@link AnalogWatchFaceService} is similar but has a ticking second hand.
+ */
+public class SweepWatchFaceService extends CanvasWatchFaceService {
+    private static final String TAG = "SweepWatchFaceService";
+
+    @Override
+    public Engine onCreateEngine() {
+        return new Engine();
+    }
+
+    private class Engine extends CanvasWatchFaceService.Engine {
+        Paint mHourPaint;
+        Paint mMinutePaint;
+        Paint mSecondPaint;
+        Paint mTickPaint;
+        boolean mMute;
+        Time mTime;
+
+        final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                mTime.clear(intent.getStringExtra("time-zone"));
+                mTime.setToNow();
+            }
+        };
+        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) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onCreate");
+            }
+            super.onCreate(holder);
+
+            setWatchFaceStyle(new WatchFaceStyle.Builder(SweepWatchFaceService.this)
+                    .setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
+                    .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
+                    .setShowSystemUiTime(false)
+                    .build());
+
+            Resources resources = SweepWatchFaceService.this.getResources();
+            Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg);
+            mBackgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();
+
+            mHourPaint = new Paint();
+            mHourPaint.setARGB(255, 200, 200, 200);
+            mHourPaint.setStrokeWidth(5.f);
+            mHourPaint.setAntiAlias(true);
+            mHourPaint.setStrokeCap(Paint.Cap.ROUND);
+
+            mMinutePaint = new Paint();
+            mMinutePaint.setARGB(255, 200, 200, 200);
+            mMinutePaint.setStrokeWidth(3.f);
+            mMinutePaint.setAntiAlias(true);
+            mMinutePaint.setStrokeCap(Paint.Cap.ROUND);
+
+            mSecondPaint = new Paint();
+            mSecondPaint.setARGB(255, 255, 0, 0);
+            mSecondPaint.setStrokeWidth(2.f);
+            mSecondPaint.setAntiAlias(true);
+            mSecondPaint.setStrokeCap(Paint.Cap.ROUND);
+
+            mTickPaint = new Paint();
+            mTickPaint.setARGB(100, 255, 255, 255);
+            mTickPaint.setStrokeWidth(2.f);
+            mTickPaint.setAntiAlias(true);
+
+            mTime = new Time();
+        }
+
+        @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);
+            }
+        }
+
+        @Override
+        public void onTimeTick() {
+            super.onTimeTick();
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onTimeTick: ambient = " + isInAmbientMode());
+            }
+            invalidate();
+        }
+
+        @Override
+        public void onAmbientModeChanged(boolean inAmbientMode) {
+            super.onAmbientModeChanged(inAmbientMode);
+            if (mLowBitAmbient) {
+                boolean antiAlias = !inAmbientMode;
+                mHourPaint.setAntiAlias(antiAlias);
+                mMinutePaint.setAntiAlias(antiAlias);
+                mSecondPaint.setAntiAlias(antiAlias);
+                mTickPaint.setAntiAlias(antiAlias);
+            }
+            invalidate();
+        }
+
+        @Override
+        public void onInterruptionFilterChanged(int interruptionFilter) {
+            super.onInterruptionFilterChanged(interruptionFilter);
+            boolean inMuteMode = (interruptionFilter == WatchFaceService.INTERRUPTION_FILTER_NONE);
+            if (mMute != inMuteMode) {
+                mMute = inMuteMode;
+                mHourPaint.setAlpha(inMuteMode ? 100 : 255);
+                mMinutePaint.setAlpha(inMuteMode ? 100 : 255);
+                mSecondPaint.setAlpha(inMuteMode ? 80 : 255);
+                invalidate();
+            }
+        }
+
+        @Override
+        public void onDraw(Canvas canvas) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "onDraw");
+            }
+            long now = System.currentTimeMillis();
+            mTime.set(now);
+            int milliseconds = (int) (now % 1000);
+
+            int width = canvas.getWidth();
+            int height = canvas.getHeight();
+
+            // 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;
+
+            // Draw the ticks.
+            float innerTickRadius = centerX - 10;
+            float outerTickRadius = centerX;
+            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);
+            }
+
+            float seconds = mTime.second + milliseconds / 1000f;
+            float secRot = seconds / 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;
+
+            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);
+            }
+
+            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.
+            if (isVisible()) {
+                invalidate();
+            }
+        }
+
+        @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();
+
+                invalidate();
+            } else {
+                unregisterReceiver();
+            }
+        }
+
+        private void registerReceiver() {
+            if (mRegisteredTimeZoneReceiver) {
+                return;
+            }
+            mRegisteredTimeZoneReceiver = true;
+            IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
+            SweepWatchFaceService.this.registerReceiver(mTimeZoneReceiver, filter);
+        }
+
+        private void unregisterReceiver() {
+            if (!mRegisteredTimeZoneReceiver) {
+                return;
+            }
+            mRegisteredTimeZoneReceiver = false;
+            SweepWatchFaceService.this.unregisterReceiver(mTimeZoneReceiver);
+        }
+    }
+}
diff --git a/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/TiltWatchFaceService.java b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/TiltWatchFaceService.java
new file mode 100644
index 0000000..ce90d77
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/java/com/example/android/wearable/watchface/TiltWatchFaceService.java
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) 2014 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.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.opengl.GLES20;
+import android.opengl.Matrix;
+import android.support.wearable.watchface.Gles2WatchFaceService;
+import android.support.wearable.watchface.WatchFaceStyle;
+import android.text.format.Time;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.SurfaceHolder;
+
+import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Sample watch face using OpenGL. The watch face is rendered using
+ * {@link Gles2ColoredTriangleList}s. The camera moves around in interactive mode and stops moving
+ * when the watch enters ambient mode.
+ */
+public class TiltWatchFaceService extends Gles2WatchFaceService {
+
+    private static final String TAG = "TiltWatchFaceService";
+
+    /** Expected frame rate in interactive mode. */
+    private static final long FPS = 60;
+
+    /** How long each frame is displayed at expected frame rate. */
+    private static final long FRAME_PERIOD_MS = TimeUnit.SECONDS.toMillis(1) / FPS;
+
+    @Override
+    public Engine onCreateEngine() {
+        return new Engine();
+    }
+
+    private class Engine extends Gles2WatchFaceService.Engine {
+        /** Cycle time before the camera motion repeats. */
+        private static final long CYCLE_PERIOD_SECONDS = 5;
+
+        /** Number of camera angles to precompute. */
+        private final int mNumCameraAngles = (int) (CYCLE_PERIOD_SECONDS * FPS);
+
+        /** Projection transformation matrix. Converts from 3D to 2D. */
+        private final float[] mProjectionMatrix = new float[16];
+
+        /**
+         * View transformation matrices to use in interactive mode. Converts from world to camera-
+         * relative coordinates. One matrix per camera position.
+         */
+        private final float[][] mViewMatrices = new float[mNumCameraAngles][16];
+
+        /** The view transformation matrix to use in ambient mode */
+        private final float[] mAmbientViewMatrix = new float[16];
+
+        /**
+         * Model transformation matrices. Converts from model-relative coordinates to world
+         * coordinates. One matrix per degree of rotation.
+         */
+        private final float[][] mModelMatrices = new float[360][16];
+
+        /**
+         * Products of {@link #mViewMatrices} and {@link #mProjectionMatrix}. One matrix per camera
+         * position.
+         */
+        private final float[][] mVpMatrices = new float[mNumCameraAngles][16];
+
+        /** The product of {@link #mAmbientViewMatrix} and {@link #mProjectionMatrix} */
+        private final float[] mAmbientVpMatrix = new float[16];
+
+        /**
+         * Product of {@link #mModelMatrices}, {@link #mViewMatrices}, and
+         * {@link #mProjectionMatrix}.
+         */
+        private final float[] mMvpMatrix = new float[16];
+
+        /** Triangles for the 4 major ticks. These are grouped together to speed up rendering. */
+        private Gles2ColoredTriangleList mMajorTickTriangles;
+
+        /** Triangles for the 8 minor ticks. These are grouped together to speed up rendering. */
+        private Gles2ColoredTriangleList mMinorTickTriangles;
+
+        /** Triangle for the second hand. */
+        private Gles2ColoredTriangleList mSecondHandTriangle;
+
+        /** Triangle for the minute hand. */
+        private Gles2ColoredTriangleList mMinuteHandTriangle;
+
+        /** Triangle for the hour hand. */
+        private Gles2ColoredTriangleList mHourHandTriangle;
+
+        private Time mTime = new Time();
+
+        /** Whether we've registered {@link #mTimeZoneReceiver}. */
+        private boolean mRegisteredTimeZoneReceiver;
+
+        private final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                mTime.clear(intent.getStringExtra("time-zone"));
+                mTime.setToNow();
+            }
+        };
+
+        @Override
+        public void onCreate(SurfaceHolder surfaceHolder) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onCreate");
+            }
+            super.onCreate(surfaceHolder);
+            setWatchFaceStyle(new WatchFaceStyle.Builder(TiltWatchFaceService.this)
+                    .setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
+                    .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
+                    .setStatusBarGravity(Gravity.RIGHT | Gravity.TOP)
+                    .setHotwordIndicatorGravity(Gravity.LEFT | Gravity.TOP)
+                    .setShowSystemUiTime(false)
+                    .build());
+        }
+
+        @Override
+        public void onGlContextCreated() {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onGlContextCreated");
+            }
+            super.onGlContextCreated();
+
+            // Create program for drawing triangles.
+            Gles2ColoredTriangleList.Program triangleProgram =
+                    new Gles2ColoredTriangleList.Program();
+
+            // We only draw triangles which all use the same program so we don't need to switch
+            // programs mid-frame. This means we can tell OpenGL to use this program only once
+            // rather than having to do so for each frame. This makes OpenGL draw faster.
+            triangleProgram.use();
+
+            // Create triangles for the ticks.
+            mMajorTickTriangles = createMajorTicks(triangleProgram);
+            mMinorTickTriangles = createMinorTicks(triangleProgram);
+
+            // Create triangles for the hands.
+            mSecondHandTriangle = createHand(
+                    triangleProgram,
+                    0.02f /* width */,
+                    1.0f /* height */,
+                    new float[]{
+                            1.0f /* red */,
+                            0.0f /* green */,
+                            0.0f /* blue */,
+                            1.0f /* alpha */
+                    }
+            );
+            mMinuteHandTriangle = createHand(
+                    triangleProgram,
+                    0.06f /* width */,
+                    0.8f /* height */,
+                    new float[]{
+                            0.7f /* red */,
+                            0.7f /* green */,
+                            0.7f /* blue */,
+                            1.0f /* alpha */
+                    }
+            );
+            mHourHandTriangle = createHand(
+                    triangleProgram,
+                    0.1f /* width */,
+                    0.5f /* height */,
+                    new float[]{
+                            0.9f /* red */,
+                            0.9f /* green */,
+                            0.9f /* blue */,
+                            1.0f /* alpha */
+                    }
+            );
+
+            // Precompute the clock angles.
+            for (int i = 0; i < mModelMatrices.length; ++i) {
+                Matrix.setRotateM(mModelMatrices[i], 0, i, 0, 0, 1);
+            }
+
+            // Precompute the camera angles.
+            for (int i = 0; i < mNumCameraAngles; ++i) {
+                // Set the camera position (View matrix). When active, move the eye around to show
+                // off that this is 3D.
+                final float cameraAngle = (float) (((float) i) / mNumCameraAngles * 2 * Math.PI);
+                final float eyeX = (float) Math.cos(cameraAngle);
+                final float eyeY = (float) Math.sin(cameraAngle);
+                Matrix.setLookAtM(mViewMatrices[i],
+                        0, // dest index
+                        eyeX, eyeY, -3, // eye
+                        0, 0, 0, // center
+                        0, 1, 0); // up vector
+            }
+
+            Matrix.setLookAtM(mAmbientViewMatrix,
+                    0, // dest index
+                    0, 0, -3, // eye
+                    0, 0, 0, // center
+                    0, 1, 0); // up vector
+        }
+
+        @Override
+        public void onGlSurfaceCreated(int width, int height) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onGlSurfaceCreated");
+            }
+            super.onGlSurfaceCreated(width, height);
+
+            // Adjust the viewport based on geometry changes such as screen rotation.
+            GLES20.glViewport(0, 0, width, height);
+
+            // Update the projection matrix based on the new aspect ratio.
+            final float aspectRatio = (float) width / height;
+            Matrix.frustumM(mProjectionMatrix,
+                    0 /* offset */,
+                    -aspectRatio /* left */,
+                    aspectRatio /* right */,
+                    -1 /* bottom */,
+                    1 /* top */,
+                    2 /* near */,
+                    7 /* far */);
+
+            // Precompute the products of Projection and View matrices for each camera angle.
+            for (int i = 0; i < mNumCameraAngles; ++i) {
+                Matrix.multiplyMM(mVpMatrices[i], 0, mProjectionMatrix, 0, mViewMatrices[i], 0);
+            }
+
+            Matrix.multiplyMM(mAmbientVpMatrix, 0, mProjectionMatrix, 0, mAmbientViewMatrix, 0);
+        }
+
+        /**
+         * Creates a triangle for a hand on the watch face.
+         *
+         * @param program program for drawing triangles
+         * @param width width of base of triangle
+         * @param length length of triangle
+         * @param color color in RGBA order, each in the range [0, 1]
+         */
+        private Gles2ColoredTriangleList createHand(Gles2ColoredTriangleList.Program program,
+                float width, float length, float[] color) {
+            // Create the data for the VBO.
+            float[] triangleCoords = new float[]{
+                    // in counterclockwise order:
+                    0, length, 0,   // top
+                    -width / 2, 0, 0,   // bottom left
+                    width / 2, 0, 0    // bottom right
+            };
+            return new Gles2ColoredTriangleList(program, triangleCoords, color);
+        }
+
+        /**
+         * Creates a triangle list for the major ticks on the watch face.
+         *
+         * @param program program for drawing triangles
+         */
+        private Gles2ColoredTriangleList createMajorTicks(
+                Gles2ColoredTriangleList.Program program) {
+            // Create the data for the VBO.
+            float[] trianglesCoords = new float[9 * 4];
+            for (int i = 0; i < 4; i++) {
+                float[] triangleCoords = getMajorTickTriangleCoords(i);
+                System.arraycopy(triangleCoords, 0, trianglesCoords, i * 9, triangleCoords.length);
+            }
+
+            return new Gles2ColoredTriangleList(program, trianglesCoords,
+                    new float[]{
+                            1.0f /* red */,
+                            1.0f /* green */,
+                            1.0f /* blue */,
+                            1.0f /* alpha */
+                    }
+            );
+        }
+
+        /**
+         * Creates a triangle list for the minor ticks on the watch face.
+         *
+         * @param program program for drawing triangles
+         */
+        private Gles2ColoredTriangleList createMinorTicks(
+                Gles2ColoredTriangleList.Program program) {
+            // Create the data for the VBO.
+            float[] trianglesCoords = new float[9 * (12 - 4)];
+            int index = 0;
+            for (int i = 0; i < 12; i++) {
+                if (i % 3 == 0) {
+                    // This is where a major tick goes, so skip it.
+                    continue;
+                }
+                float[] triangleCoords = getMinorTickTriangleCoords(i);
+                System.arraycopy(triangleCoords, 0, trianglesCoords, index, triangleCoords.length);
+                index += 9;
+            }
+
+            return new Gles2ColoredTriangleList(program, trianglesCoords,
+                    new float[]{
+                            0.5f /* red */,
+                            0.5f /* green */,
+                            0.5f /* blue */,
+                            1.0f /* alpha */
+                    }
+            );
+        }
+
+        private float[] getMajorTickTriangleCoords(int index) {
+            return getTickTriangleCoords(0.03f /* width */, 0.09f /* length */,
+                    index * 360 / 4 /* angleDegrees */);
+        }
+
+        private float[] getMinorTickTriangleCoords(int index) {
+            return getTickTriangleCoords(0.02f /* width */, 0.06f /* length */,
+                    index * 360 / 12 /* angleDegrees */);
+        }
+
+        private float[] getTickTriangleCoords(float width, float length, int angleDegrees) {
+            // Create the data for the VBO.
+            float[] coords = new float[]{
+                    // in counterclockwise order:
+                    0, 1, 0,   // top
+                    width / 2, length + 1, 0,   // bottom left
+                    -width / 2, length + 1, 0    // bottom right
+            };
+
+            rotateCoords(coords, angleDegrees);
+            return coords;
+        }
+
+        /**
+         * Destructively rotates the given coordinates in the XY plane about the origin by the given
+         * angle.
+         *
+         * @param coords flattened 3D coordinates
+         * @param angleDegrees angle in degrees clockwise when viewed from negative infinity on the
+         *                     Z axis
+         */
+        private void rotateCoords(float[] coords, int angleDegrees) {
+            double angleRadians = Math.toRadians(angleDegrees);
+            double cos = Math.cos(angleRadians);
+            double sin = Math.sin(angleRadians);
+            for (int i = 0; i < coords.length; i += 3) {
+                float x = coords[i];
+                float y = coords[i + 1];
+                coords[i] = (float) (cos * x - sin * y);
+                coords[i + 1] = (float) (sin * x + cos * y);
+            }
+        }
+
+        @Override
+        public void onAmbientModeChanged(boolean inAmbientMode) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onAmbientModeChanged: " + inAmbientMode);
+            }
+            super.onAmbientModeChanged(inAmbientMode);
+            invalidate();
+        }
+
+        @Override
+        public void onVisibilityChanged(boolean visible) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onVisibilityChanged: " + visible);
+            }
+            super.onVisibilityChanged(visible);
+            if (visible) {
+                registerReceiver();
+
+                // Update time zone in case it changed while we were detached.
+                mTime.clear(TimeZone.getDefault().getID());
+                mTime.setToNow();
+
+                invalidate();
+            } else {
+                unregisterReceiver();
+            }
+        }
+
+        private void registerReceiver() {
+            if (mRegisteredTimeZoneReceiver) {
+                return;
+            }
+            mRegisteredTimeZoneReceiver = true;
+            IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
+            TiltWatchFaceService.this.registerReceiver(mTimeZoneReceiver, filter);
+        }
+
+        private void unregisterReceiver() {
+            if (!mRegisteredTimeZoneReceiver) {
+                return;
+            }
+            mRegisteredTimeZoneReceiver = false;
+            TiltWatchFaceService.this.unregisterReceiver(mTimeZoneReceiver);
+        }
+
+        @Override
+        public void onTimeTick() {
+            super.onTimeTick();
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onTimeTick: ambient = " + isInAmbientMode());
+            }
+            invalidate();
+        }
+
+        @Override
+        public void onDraw() {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "onDraw");
+            }
+            super.onDraw();
+            final float[] vpMatrix;
+
+            // Draw background color and select the appropriate view projection matrix. The
+            // background should always be black in ambient mode. The view projection matrix used is
+            // overhead in ambient. In interactive mode, it's tilted depending on the current time.
+            if (isInAmbientMode()) {
+                GLES20.glClearColor(0, 0, 0, 1);
+                vpMatrix = mAmbientVpMatrix;
+            } else {
+                GLES20.glClearColor(0.5f, 0.2f, 0.2f, 1);
+                final int cameraIndex =
+                        (int) ((System.currentTimeMillis() / FRAME_PERIOD_MS) % mNumCameraAngles);
+                vpMatrix = mVpMatrices[cameraIndex];
+            }
+            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+
+            // Compute angle indices for the three hands.
+            mTime.setToNow();
+            final int secIndex = mTime.second * 360 / 60;
+            final int minIndex = mTime.minute * 360 / 60;
+            final int hoursIndex = (mTime.hour % 12) * 360 / 12 + mTime.minute * 360 / 60 / 12;
+
+            // Draw triangles from back to front. Don't draw the second hand in ambient mode.
+            {
+                // Combine the model matrix with the projection and camera view.
+                Matrix.multiplyMM(mMvpMatrix, 0, vpMatrix, 0, mModelMatrices[hoursIndex], 0);
+
+                // Draw the triangle.
+                mHourHandTriangle.draw(mMvpMatrix);
+            }
+            {
+                // Combine the model matrix with the projection and camera view.
+                Matrix.multiplyMM(mMvpMatrix, 0, vpMatrix, 0, mModelMatrices[minIndex], 0);
+
+                // Draw the triangle.
+                mMinuteHandTriangle.draw(mMvpMatrix);
+            }
+            if (!isInAmbientMode()) {
+                // Combine the model matrix with the projection and camera view.
+                Matrix.multiplyMM(mMvpMatrix, 0, vpMatrix, 0, mModelMatrices[secIndex], 0);
+
+                // Draw the triangle.
+                mSecondHandTriangle.draw(mMvpMatrix);
+            }
+            {
+                // Draw the major and minor ticks.
+                mMajorTickTriangles.draw(vpMatrix);
+                mMinorTickTriangles.draw(vpMatrix);
+            }
+
+            // Draw every frame as long as we're visible.
+            if (isVisible()) {
+                invalidate();
+            }
+        }
+    }
+}
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/bg.png b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/bg.png
new file mode 100644
index 0000000..5199af2
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/bg.png
Binary files differ
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/ic_launcher.png b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..589f229
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/preview_analog.png b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/preview_analog.png
new file mode 100644
index 0000000..ed6960d
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/preview_analog.png
Binary files differ
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/preview_calendar.png b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/preview_calendar.png
new file mode 100644
index 0000000..928aa1f
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/preview_calendar.png
Binary files differ
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/preview_card_bounds.png b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/preview_card_bounds.png
new file mode 100644
index 0000000..f87b6c5
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/preview_card_bounds.png
Binary files differ
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/preview_digital.png b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/preview_digital.png
new file mode 100644
index 0000000..4853a64
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/preview_digital.png
Binary files differ
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/preview_tilt.png b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/preview_tilt.png
new file mode 100644
index 0000000..aab5f18
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-hdpi/preview_tilt.png
Binary files differ
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/drawable-mdpi/ic_launcher.png b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..77dd571
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/drawable-xhdpi/ic_launcher.png b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..fe34ebe
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/drawable-xxhdpi/ic_launcher.png b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..ab80bcd
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/layout/activity_digital_config.xml b/wearable/wear/WatchFace/Wearable/src/main/res/layout/activity_digital_config.xml
new file mode 100644
index 0000000..eef7aae
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/layout/activity_digital_config.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:background="#ffffff">
+    <TextView
+        android:id="@+id/header"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="16dp"
+        android:layout_marginTop="14dp"
+        android:layout_gravity="center_horizontal"
+        android:textSize="22sp"
+        android:textColor="#a2a2a2"
+        android:text="@string/digital_background_color"
+        android:fontFamily="sans-serif-condensed-light"/>
+    <android.support.wearable.view.WearableListView
+        android:id="@+id/color_picker"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@android:color/transparent"/>
+</LinearLayout>
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/layout/color_picker_item.xml b/wearable/wear/WatchFace/Wearable/src/main/res/layout/color_picker_item.xml
new file mode 100644
index 0000000..e7edb39
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/layout/color_picker_item.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/label"
+    android:fontFamily="sans-serif-condensed-light"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center_horizontal"
+    android:paddingTop="20dp"
+    android:paddingBottom="20dp"
+    android:textColor="#000000"
+    android:textSize="18sp"/>
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/values/color.xml b/wearable/wear/WatchFace/Wearable/src/main/res/values/color.xml
new file mode 100644
index 0000000..2ba1355
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/values/color.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<resources>
+    <color name="digital_am_pm">#aaaaa0</color>
+    <color name="digital_colons">#aaaaa0</color>
+</resources>
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/values/dimens.xml b/wearable/wear/WatchFace/Wearable/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..b9c4c86
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/values/dimens.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<resources>
+    <dimen name="digital_text_size">40dp</dimen>
+    <dimen name="digital_text_size_round">45dp</dimen>
+    <dimen name="digital_am_pm_size">25dp</dimen>
+    <dimen name="digital_am_pm_size_round">30dp</dimen>
+    <dimen name="digital_x_offset">15dp</dimen>
+    <dimen name="digital_x_offset_round">25dp</dimen>
+    <dimen name="digital_y_offset">90dp</dimen>
+    <dimen name="digital_config_color_picker_item_margin">32dp</dimen>
+</resources>
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/values/strings.xml b/wearable/wear/WatchFace/Wearable/src/main/res/values/strings.xml
new file mode 100644
index 0000000..e54591f
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/values/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<resources>
+    <string name="app_name">WatchFace</string>
+    <string name="tilt_name">Sample Tilt</string>
+    <string name="analog_name">Sample Analog</string>
+    <string name="sweep_name">Sample Sweep</string>
+    <string name="card_bounds_name">Sample Card Bounds</string>
+    <string name="digital_name">Sample Digital</string>
+    <string name="digital_background_color">Background color</string>
+    <string name="digital_config_name">Digital watch face configuration</string>
+    <string name="digital_am">AM</string>
+    <string name="digital_pm">PM</string>
+    <string name="calendar_name">Sample Calendar</string>
+    <plurals name="calendar_meetings">
+        <item quantity="one">&lt;br&gt;&lt;br&gt;&lt;br&gt;You have &lt;b&gt;%1$d&lt;/b&gt; meeting in the next 24 hours.</item>
+        <item quantity="other">&lt;br&gt;&lt;br&gt;&lt;br&gt;You have &lt;b&gt;%1$d&lt;/b&gt; meetings in the next 24 hours.</item>
+    </plurals>
+
+    <!-- TODO: this should be shared (needs covering all the samples with Gradle build model) -->
+    <string name="color_black">Black</string>
+    <string name="color_blue">Blue</string>
+    <string name="color_gray">Gray</string>
+    <string name="color_green">Green</string>
+    <string name="color_navy">Navy</string>
+    <string name="color_red">Red</string>
+    <string name="color_white">White</string>
+
+    <string-array name="color_array">
+        <item>@string/color_black</item>
+        <item>@string/color_blue</item>
+        <item>@string/color_gray</item>
+        <item>@string/color_green</item>
+        <item>@string/color_navy</item>
+        <item>@string/color_red</item>
+        <item>@string/color_white</item>
+    </string-array>
+</resources>
diff --git a/wearable/wear/WatchFace/Wearable/src/main/res/xml/watch_face.xml b/wearable/wear/WatchFace/Wearable/src/main/res/xml/watch_face.xml
new file mode 100644
index 0000000..aa2e343
--- /dev/null
+++ b/wearable/wear/WatchFace/Wearable/src/main/res/xml/watch_face.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<wallpaper xmlns:android="http://schemas.android.com/apk/res/android" />
diff --git a/wearable/wear/WatchFace/build.gradle b/wearable/wear/WatchFace/build.gradle
new file mode 100644
index 0000000..be1fa82
--- /dev/null
+++ b/wearable/wear/WatchFace/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+  pathToBuild "../../../../../build"
+  pathToSamplesCommon "../../../common"
+}
+apply from: "../../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/wearable/wear/WatchFace/buildSrc/build.gradle b/wearable/wear/WatchFace/buildSrc/build.gradle
new file mode 100644
index 0000000..e344a8c
--- /dev/null
+++ b/wearable/wear/WatchFace/buildSrc/build.gradle
@@ -0,0 +1,18 @@
+
+
+
+repositories {
+    mavenCentral()
+}
+dependencies {
+    compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+    main {
+        groovy {
+            srcDir new File(rootDir, "../../../../../../build/buildSrc/src/main/groovy")
+        }
+    }
+}
+
diff --git a/wearable/wear/WatchFace/gradle/wrapper/gradle-wrapper.jar b/wearable/wear/WatchFace/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8c0fb64
--- /dev/null
+++ b/wearable/wear/WatchFace/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/wearable/wear/WatchFace/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/WatchFace/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..d7f03cf
--- /dev/null
+++ b/wearable/wear/WatchFace/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-bin.zip
diff --git a/wearable/wear/WatchFace/gradlew b/wearable/wear/WatchFace/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/wearable/wear/WatchFace/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/wearable/wear/WatchFace/gradlew.bat b/wearable/wear/WatchFace/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/wearable/wear/WatchFace/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/wearable/wear/WatchFace/screenshots/analog_and_sweep_face.png b/wearable/wear/WatchFace/screenshots/analog_and_sweep_face.png
new file mode 100644
index 0000000..df0820e
--- /dev/null
+++ b/wearable/wear/WatchFace/screenshots/analog_and_sweep_face.png
Binary files differ
diff --git a/wearable/wear/WatchFace/screenshots/calendar_face.png b/wearable/wear/WatchFace/screenshots/calendar_face.png
new file mode 100644
index 0000000..94214c0
--- /dev/null
+++ b/wearable/wear/WatchFace/screenshots/calendar_face.png
Binary files differ
diff --git a/wearable/wear/WatchFace/screenshots/card_bounds_face.png b/wearable/wear/WatchFace/screenshots/card_bounds_face.png
new file mode 100644
index 0000000..0ee827e
--- /dev/null
+++ b/wearable/wear/WatchFace/screenshots/card_bounds_face.png
Binary files differ
diff --git a/wearable/wear/WatchFace/screenshots/card_bounds_face2.png b/wearable/wear/WatchFace/screenshots/card_bounds_face2.png
new file mode 100644
index 0000000..c9c107e
--- /dev/null
+++ b/wearable/wear/WatchFace/screenshots/card_bounds_face2.png
Binary files differ
diff --git a/wearable/wear/WatchFace/screenshots/digital_face.png b/wearable/wear/WatchFace/screenshots/digital_face.png
new file mode 100644
index 0000000..f2d1723
--- /dev/null
+++ b/wearable/wear/WatchFace/screenshots/digital_face.png
Binary files differ
diff --git a/wearable/wear/WatchFace/screenshots/digital_phoneside_config.png b/wearable/wear/WatchFace/screenshots/digital_phoneside_config.png
new file mode 100644
index 0000000..f614d10
--- /dev/null
+++ b/wearable/wear/WatchFace/screenshots/digital_phoneside_config.png
Binary files differ
diff --git a/wearable/wear/WatchFace/screenshots/digital_watchside_config.png b/wearable/wear/WatchFace/screenshots/digital_watchside_config.png
new file mode 100644
index 0000000..d2813c4
--- /dev/null
+++ b/wearable/wear/WatchFace/screenshots/digital_watchside_config.png
Binary files differ
diff --git a/wearable/wear/WatchFace/screenshots/tilt_face.png b/wearable/wear/WatchFace/screenshots/tilt_face.png
new file mode 100644
index 0000000..69601a7
--- /dev/null
+++ b/wearable/wear/WatchFace/screenshots/tilt_face.png
Binary files differ
diff --git a/wearable/wear/WatchFace/settings.gradle b/wearable/wear/WatchFace/settings.gradle
new file mode 100644
index 0000000..19d00ac
--- /dev/null
+++ b/wearable/wear/WatchFace/settings.gradle
@@ -0,0 +1 @@
+include ':Application', ':Wearable'
diff --git a/wearable/wear/WatchFace/template-params.xml b/wearable/wear/WatchFace/template-params.xml
new file mode 100644
index 0000000..0e6a7b3
--- /dev/null
+++ b/wearable/wear/WatchFace/template-params.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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.
+-->
+
+
+
+<sample>
+    <name>WatchFace</name>
+    <group>Wearable</group>
+    <package>com.example.android.wearable.watchface</package>
+
+
+
+    <!-- change minSdk if needed-->
+    <minSdk>18</minSdk>
+
+    <dependency>com.google.android.support:wearable:1.1.+</dependency>
+
+
+    <strings>
+        <intro>
+            <![CDATA[
+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.
+            ]]>
+        </intro>
+    </strings>
+
+    <template src="base"/>
+    <template src="Wear"/>
+
+</sample>
diff --git a/wearable/wear/WatchViewStub/Application/src/main/AndroidManifest.xml b/wearable/wear/WatchViewStub/Application/src/main/AndroidManifest.xml
index d33b81f..ce85081 100644
--- a/wearable/wear/WatchViewStub/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/WatchViewStub/Application/src/main/AndroidManifest.xml
@@ -19,7 +19,7 @@
     package="com.example.android.google.wearable.watchviewstub">
 
     <uses-sdk android:minSdkVersion="18"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <application android:allowBackup="true"
         android:label="@string/app_name">
diff --git a/wearable/wear/WatchViewStub/Wearable/src/main/AndroidManifest.xml b/wearable/wear/WatchViewStub/Wearable/src/main/AndroidManifest.xml
index baa3f78..33a266d 100644
--- a/wearable/wear/WatchViewStub/Wearable/src/main/AndroidManifest.xml
+++ b/wearable/wear/WatchViewStub/Wearable/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
         package="com.example.android.google.wearable.watchviewstub" >
 
     <uses-sdk android:minSdkVersion="20"
-              android:targetSdkVersion="20" />
+              android:targetSdkVersion="21" />
 
     <uses-feature android:name="android.hardware.type.watch" />