Add browseable samples for Clockwork Beryl

Bug: 17473824
Change-Id: Id4c637733c491ac71bb6e269f55939c082fb0994
diff --git a/samples/browseable/ElizaChat/Application/AndroidManifest.xml b/samples/browseable/ElizaChat/Application/AndroidManifest.xml
new file mode 100644
index 0000000..e653fa9
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/AndroidManifest.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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.elizachat" >
+
+    <uses-sdk android:minSdkVersion="19"
+              android:targetSdkVersion="19" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_app_eliza"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <service
+            android:name=".ResponderService">
+            <intent-filter>
+                <action android:name="com.example.android.elizachat.REPLY" />
+                <action android:name="com.example.android.elizachat.CONVERSATION" />
+            </intent-filter>
+        </service>
+    </application>
+
+</manifest>
diff --git a/samples/browseable/ElizaChat/Application/res/drawable-hdpi/ic_full_reply.png b/samples/browseable/ElizaChat/Application/res/drawable-hdpi/ic_full_reply.png
new file mode 100644
index 0000000..66388d5
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/drawable-hdpi/ic_full_reply.png
Binary files differ
diff --git a/samples/browseable/ElizaChat/Application/res/drawable-hdpi/tile.9.png b/samples/browseable/ElizaChat/Application/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/ElizaChat/Application/res/drawable-mdpi/ic_full_reply.png b/samples/browseable/ElizaChat/Application/res/drawable-mdpi/ic_full_reply.png
new file mode 100644
index 0000000..60ce9f9
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/drawable-mdpi/ic_full_reply.png
Binary files differ
diff --git a/samples/browseable/ElizaChat/Application/res/drawable-nodpi/bg_eliza.png b/samples/browseable/ElizaChat/Application/res/drawable-nodpi/bg_eliza.png
new file mode 100644
index 0000000..3bbdf48
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/drawable-nodpi/bg_eliza.png
Binary files differ
diff --git a/samples/browseable/ElizaChat/Application/res/drawable-xhdpi/ic_full_reply.png b/samples/browseable/ElizaChat/Application/res/drawable-xhdpi/ic_full_reply.png
new file mode 100644
index 0000000..dba6fa7
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/drawable-xhdpi/ic_full_reply.png
Binary files differ
diff --git a/samples/browseable/ElizaChat/Application/res/layout/activity_main.xml b/samples/browseable/ElizaChat/Application/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/ElizaChat/Application/res/layout/main.xml b/samples/browseable/ElizaChat/Application/res/layout/main.xml
new file mode 100644
index 0000000..6ffed8e
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/layout/main.xml
@@ -0,0 +1,17 @@
+<ScrollView 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"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    tools:context="com.example.android.wearable.elizachat.MainActivity$PlaceholderFragment"
+    android:orientation="vertical" >
+
+    <TextView
+        android:id="@+id/history"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
+</ScrollView>
diff --git a/samples/browseable/ElizaChat/Application/res/menu/main.xml b/samples/browseable/ElizaChat/Application/res/menu/main.xml
new file mode 100644
index 0000000..b8e1ef2
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/menu/main.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/action_stop_service"
+        android:orderInCategory="100"
+        android:showAsAction="always|withText"
+        android:title="@string/stop_service" />
+
+</menu>
diff --git a/samples/browseable/ElizaChat/Application/res/mipmap-hdpi/ic_app_eliza.png b/samples/browseable/ElizaChat/Application/res/mipmap-hdpi/ic_app_eliza.png
new file mode 100644
index 0000000..1bdb147
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/mipmap-hdpi/ic_app_eliza.png
Binary files differ
diff --git a/samples/browseable/ElizaChat/Application/res/mipmap-mdpi/ic_app_eliza.png b/samples/browseable/ElizaChat/Application/res/mipmap-mdpi/ic_app_eliza.png
new file mode 100644
index 0000000..2e0e198
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/mipmap-mdpi/ic_app_eliza.png
Binary files differ
diff --git a/samples/browseable/ElizaChat/Application/res/mipmap-xhdpi/ic_app_eliza.png b/samples/browseable/ElizaChat/Application/res/mipmap-xhdpi/ic_app_eliza.png
new file mode 100644
index 0000000..8d0f436
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/mipmap-xhdpi/ic_app_eliza.png
Binary files differ
diff --git a/samples/browseable/ElizaChat/Application/res/mipmap-xxhdpi/ic_app_eliza.png b/samples/browseable/ElizaChat/Application/res/mipmap-xxhdpi/ic_app_eliza.png
new file mode 100644
index 0000000..e72b967
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/mipmap-xxhdpi/ic_app_eliza.png
Binary files differ
diff --git a/samples/browseable/ElizaChat/Application/res/mipmap-xxxhdpi/ic_app_eliza.png b/samples/browseable/ElizaChat/Application/res/mipmap-xxxhdpi/ic_app_eliza.png
new file mode 100644
index 0000000..06ea079
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/mipmap-xxxhdpi/ic_app_eliza.png
Binary files differ
diff --git a/samples/browseable/ElizaChat/Application/res/values-sw600dp/template-dimens.xml b/samples/browseable/ElizaChat/Application/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  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.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ElizaChat/Application/res/values-sw600dp/template-styles.xml b/samples/browseable/ElizaChat/Application/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+  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.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/ElizaChat/Application/res/values-v11/template-styles.xml b/samples/browseable/ElizaChat/Application/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+  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.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/ElizaChat/Application/res/values/base-strings.xml b/samples/browseable/ElizaChat/Application/res/values/base-strings.xml
new file mode 100644
index 0000000..be29a5b
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/values/base-strings.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<resources>
+    <string name="app_name">ElizaChat</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This sample is a phone application that provides a chat experience in which users can respond to
+            messages with a quick voice response. New messages create a notification with a "Reply" action.
+            The notification is bridged from phone to wearable, and selecting the "Reply" action on the
+            wearable opens the voice transcription UI allowing the user to speak a response.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/ElizaChat/Application/res/values/dimens.xml b/samples/browseable/ElizaChat/Application/res/values/dimens.xml
new file mode 100644
index 0000000..a1e9cfe
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/values/dimens.xml
@@ -0,0 +1,21 @@
+<?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>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>
diff --git a/samples/browseable/ElizaChat/Application/res/values/strings.xml b/samples/browseable/ElizaChat/Application/res/values/strings.xml
new file mode 100644
index 0000000..9a5c9d7
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/values/strings.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>
+
+    <string name="send_notification">Send notification!</string>
+    <string name="eliza">Eliza</string>
+    <string name="answer_eliza">Answer Eliza</string>
+    <string name="reply">Reply</string>
+    <string name="stop_service">End Chat Session</string>
+
+</resources>
diff --git a/samples/browseable/ElizaChat/Application/res/values/template-dimens.xml b/samples/browseable/ElizaChat/Application/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  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.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ElizaChat/Application/res/values/template-styles.xml b/samples/browseable/ElizaChat/Application/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+  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.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/ElizaChat/Application/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/ElizaChat/Application/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 0000000..3228927
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+    public static final String TAG = "SampleActivityBase";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    protected  void onStart() {
+        super.onStart();
+        initializeLogging();
+    }
+
+    /** Set up targets to receive log data */
+    public void initializeLogging() {
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        // Wraps Android's native log framework
+        LogWrapper logWrapper = new LogWrapper();
+        Log.setLogNode(logWrapper);
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/ElizaChat/Application/src/com.example.android.common/logger/Log.java b/samples/browseable/ElizaChat/Application/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/ElizaChat/Application/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/ElizaChat/Application/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* 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.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/ElizaChat/Application/src/com.example.android.common/logger/LogNode.java b/samples/browseable/ElizaChat/Application/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/ElizaChat/Application/src/com.example.android.common/logger/LogView.java b/samples/browseable/ElizaChat/Application/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/ElizaChat/Application/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/ElizaChat/Application/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/ElizaChat/Application/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/ElizaChat/Application/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/ElizaChat/Application/src/com.example.android.elizachat/ElizaResponder.java b/samples/browseable/ElizaChat/Application/src/com.example.android.elizachat/ElizaResponder.java
new file mode 100644
index 0000000..e87f6de
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/src/com.example.android.elizachat/ElizaResponder.java
@@ -0,0 +1,168 @@
+/*
+ * 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.elizachat;
+
+import android.text.TextUtils;
+
+/**
+ * A basic chat bot based on ELIZA, one of the earliest programs to employ primitive natural
+ * language processing. Like ELIZA, this bot can simulate a Rogerian psychotherapist using a
+ * collection of vague and generic responses.
+ */
+public class ElizaResponder {
+
+    private static final String[] CONVERSATION_KEYWORDS = {
+            "CAN YOU", "CAN I", "YOU ARE", "YOURE", "I DONT", "I FEEL", "WHY DONT YOU", "WHY CANT I",
+            "ARE YOU", "I CANT", "I AM", " IM ", "YOU", "I WANT", "WHAT", "HOW", "WHO", "WHERE",
+            "WHEN", "WHY", "NAME", "CAUSE", "SORRY", "DREAM", "HELLO", "HI", "MAYBE", "NO", "YOUR",
+            "ALWAYS", "THINK", "ALIKE", "YES", "FRIEND", "COMPUTER", "NOKEYFOUND" };
+
+    private static String[] WORDS_TO_REPLACE = {"ARE","AM","WERE","WAS","YOU","I","YOUR","MY",
+            "IVE","YOUVE","IM","YOURE", "YOU", "ME"};
+
+    private static String[] QUESTIONS = {
+            "DON'T YOU BELIEVE THAT I CAN.", "PERHAPS YOU WOULD LIKE TO BE ABLE TO.",
+            "YOU WANT ME TO BE ABLE TO*", "PERHAPS YOU DON'T WANT TO*",
+            "DO YOU WANT TO BE ABLE TO*", "WHAT MAKES YOU THINK I AM*",
+            "DOES IT PLEASE YOU TO BELIEVE I AM*", "PERHAPS YOU WOULD LIKE TO BE*",
+            "DO YOU SOMETIMES WISH YOU WERE*", "DON'T YOU REALLY*", "WHY DON'T YOU*",
+            "DO YOU WISH TO BE ABLE TO*", "DOES THAT TROUBLE YOU?",
+            "TELL ME MORE ABOUT SUCH FEELINGS*", "DO YOU OFTEN FEEL*",
+            "DO YOU ENJOY FEELING*", "DO YOU REALLY BELIEVE I DON'T*",
+            "PERHAPS IN TIME I WILL*", "DO YOU WANT ME TO*",
+            "DO YOU THINK YOU SHOULD BE ABLE TO*", "WHY CAN'T YOU*",
+            "WHAT MAKES YOU WONDER WHETHER OR NOT I AM*",
+            "WOULD YOU PREFER IF I WERE NOT*", "PERHAPS IN YOUR FANTASIES I AM*",
+            "HOW DO YOU KNOW YOU CAN'T*", "HAVE YOU TRIED?", "PERHAPS YOU CAN NOW*",
+            "DID YOU COME TO ME BECAUSE YOU ARE*", "HOW LONG HAVE YOU BEEN*",
+            "DO YOU BELIEVE IT IS NORMAL TO BE*", "DO YOU ENJOY BEING*",
+            "I AM MORE INTERESTED IN TALKING ABOUT YOU.", "OH, I*",
+            "ARE YOU REALLY SO INTERESTED IN SOMEONE LIKE ME?",
+            "WHAT WOULD IT MEAN TO YOU IF YOU GOT*", "WHY DO YOU WANT*",
+            "SUPPOSE YOU SOON GOT*", "WHAT IF YOU NEVER GOT*", "I SOMETIMES ALSO WANT*",
+            "WHY DO YOU ASK?", "DOES THAT QUESTION INTEREST YOU?",
+            "WHAT ANSWER WOULD PLEASE YOU THE MOST?", "WHAT DO YOU THINK?",
+            "ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
+            "WHAT IS IT THAT YOU REALLY WANT TO KNOW?", "HAVE YOU ASKED ANYONE ELSE?",
+            "HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
+            "WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?", "WE CAN KEEP THIS ANONYMOUS.",
+            "NO NEED TO SPECIFY ANY NAMES-- PLEASE GO ON.", "IS THAT THE REAL REASON?",
+            "DON'T ANY OTHER REASONS COME TO MIND?",
+            "DOES THAT REASON EXPLAIN ANYTHING ELSE?", "WHAT OTHER REASONS MIGHT THERE BE?",
+            "PLEASE DON'T APOLOGIZE.", "APOLOGIES ARE NOT NECESSARY.",
+            "WHAT FEELINGS DO YOU HAVE WHEN YOU APOLOGIZE?", "NO NEED TO BE DEFENSIVE!",
+            "WHAT DOES THAT DREAM SUGGEST TO YOU?", "DO YOU DREAM OFTEN?",
+            "WHAT PERSONS APPEAR IN YOUR DREAMS?", "DO YOU HAVE PLEASANT DREAMS?",
+            "HOW DO YOU DO ... PLEASE STATE YOUR PROBLEM.", "YOU DON'T SEEM QUITE CERTAIN.",
+            "WHY THE UNCERTAIN TONE?", "LET'S TRY TO KEEP THIS POSITIVE.", "YOU AREN'T SURE?",
+            "DON'T YOU KNOW?", "IS THAT A DEFINITE NO OR MIGHT YOU CHANGE YOUR MIND?",
+            "I AM SENSING SOME NEGATIVITY.", "WHY NOT?", "ARE YOU SURE?", "WHY NO?",
+            "WHY ARE YOU CONCERNED ABOUT MY*", "WHAT ABOUT YOUR OWN*",
+            "CAN'T YOU THINK OF A SPECIFIC EXAMPLE?", "WHEN?", "WHAT ARE YOU THINKING OF?",
+            "REALLY. ALWAYS?", "DO YOU REALLY THINK SO?", "BUT YOU ARE NOT SURE YOU.",
+            "BELIEVE IN YOURSELF.", "IN WHAT WAY?", "WHAT RESEMBLANCE DO YOU SEE?",
+            "WHAT DOES THE SIMILARITY SUGGEST TO YOU?",
+            "WHAT OTHER CONNECTIONS DO YOU SEE?", "COULD THERE REALLY BE SOME CONNECTION?",
+            "HOW?", "YOU SEEM QUITE POSITIVE.", "ARE YOU SURE?", "I SEE.", "I UNDERSTAND.",
+            "TELL ME ABOUT YOUR FRIENDS.", "ARE YOU WORRIED ABOUT YOUR FRIENDS?",
+            "DO YOUR FRIENDS EVER GIVE YOU A HARD TIME?", "WHAT DO YOU LIKE ABOUT YOUR FRIENDS?",
+            "DO YOU LOVE YOUR FRIENDS?", "PERHAPS YOUR LOVE FOR FRIENDS WORRIES YOU.",
+            "DO COMPUTERS EXCITE YOU?", "ARE YOU TALKING ABOUT ME IN PARTICULAR?",
+            "HOW DO YOU LIKE YOUR WATCH?", "WHY DO YOU MENTION COMPUTERS?",
+            "DO YOU FIND MACHINES AS FASCINATING AS I DO?",
+            "DON'T YOU THINK COMPUTERS CAN HELP PEOPLE?",
+            "WHAT ABOUT MACHINES EXCITES YOU THE MOST?",
+            "HEY THERE, HOW CAN I HELP YOU?",
+            "WHAT DOES THAT SUGGEST TO YOU?", "I SEE.",
+            "I'M NOT SURE I UNDERSTAND YOU FULLY.", "COME COME ELUCIDATE YOUR THOUGHTS.",
+            "CAN YOU ELABORATE ON THAT?", "THAT IS QUITE INTERESTING."};
+
+    private static char[] CONVERSATION_TO_RESPONSES_MAP = {
+            1,3,4,2,6,4,6,4,10,4,14,3,17,3,20,2,22,3,25,3,
+            28,4,28,4,32,3,35,5,40,9,40,9,40,9,40,9,40,9,40,9,
+            49,2,51,4,55,4,59,4,63,1,63,1,64,5,69,5,74,2,76,4,
+            80,3,83,7,90,3,93,6,99,7,106,6};
+
+    private int[] responseStarts = new int[36];
+    private int[] responseCurrentIndices = new int[36];
+    private int[] responseEnds = new int[36];
+    private String previousInput = null;
+
+    public ElizaResponder() {
+        for (int i = 0; i < CONVERSATION_TO_RESPONSES_MAP.length / 2; i++) {
+            responseStarts[i] = CONVERSATION_TO_RESPONSES_MAP[2 * i];
+            responseCurrentIndices[i] = CONVERSATION_TO_RESPONSES_MAP[2 * i];
+            responseEnds[i] = responseStarts[i] + CONVERSATION_TO_RESPONSES_MAP[2 * i  + 1];
+        }
+    }
+
+    public String elzTalk(String input) {
+        if (null == input) {
+            input = "";
+        }
+        String result = "";
+
+        input = " " + input.toUpperCase().replace("\'", "") + " ";
+
+        if (previousInput != null && input.equals(previousInput)) {
+            return "DIDN'T YOU JUST SAY THAT?\n";
+        }
+        previousInput = input;
+
+        int keywordIndex = 0;
+        for (; keywordIndex < CONVERSATION_KEYWORDS.length; ++keywordIndex) {
+            int index = input.indexOf(CONVERSATION_KEYWORDS[keywordIndex]);
+            if (index != -1) {
+                break;
+            }
+        }
+
+        String afterKeyword = "";
+        if (keywordIndex == CONVERSATION_KEYWORDS.length) {
+            keywordIndex = 35;
+        } else {
+            int index = input.indexOf(CONVERSATION_KEYWORDS[keywordIndex]);
+            afterKeyword = input.substring(index + CONVERSATION_KEYWORDS[keywordIndex].length());
+            String[] parts = afterKeyword.split("\\s+");
+            for (int i = 0; i < WORDS_TO_REPLACE.length / 2; i++) {
+                String first = WORDS_TO_REPLACE[i * 2];
+                String second = WORDS_TO_REPLACE[i * 2 + 1];
+                for (int j = 0; j < parts.length; ++j) {
+                    if (parts[j].equals(first)) {
+                        parts[j] = second;
+                    } else if (parts[j].equals(second)) {
+                        parts[j] = first;
+                    }
+                }
+            }
+            afterKeyword = TextUtils.join(" ", parts);
+        }
+
+        String question = QUESTIONS[responseCurrentIndices[keywordIndex] - 1];
+        responseCurrentIndices[keywordIndex] = responseCurrentIndices[keywordIndex] + 1;
+        if (responseCurrentIndices[keywordIndex] > responseEnds[keywordIndex]) {
+            responseCurrentIndices[keywordIndex] = responseStarts[keywordIndex];
+        }
+        result += question;
+        if (result.endsWith("*")) {
+            result = result.substring(0, result.length() - 1);
+            result += " " + afterKeyword;
+        }
+
+        return result;
+    }
+}
diff --git a/samples/browseable/ElizaChat/Application/src/com.example.android.elizachat/MainActivity.java b/samples/browseable/ElizaChat/Application/src/com.example.android.elizachat/MainActivity.java
new file mode 100644
index 0000000..421dcb8
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/src/com.example.android.elizachat/MainActivity.java
@@ -0,0 +1,107 @@
+/*
+ * 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.elizachat;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.support.v4.content.LocalBroadcastManager;
+import android.text.TextUtils;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.TextView;
+
+public class MainActivity extends Activity {
+
+    @SuppressWarnings("unused")
+    private static final String TAG = "MainActivity";
+
+    public static final String EXTRA_MESSAGE = "message";
+
+    public static final String ACTION_NOTIFY = "com.example.android.elizachat.NOTIFY";
+
+    public static final String ACTION_GET_CONVERSATION
+            = "com.example.android.elizachat.CONVERSATION";
+
+    private BroadcastReceiver mReceiver;
+
+    private TextView mHistoryView;
+
+    @Override
+    protected void onCreate(Bundle saved) {
+        super.onCreate(saved);
+        setContentView(R.layout.main);
+        mReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                processMessage(intent);
+            }
+        };
+        mHistoryView = (TextView) findViewById(R.id.history);
+        startResponderService();
+    }
+
+    private void startResponderService() {
+        Intent serviceIntent = new Intent(ResponderService.ACTION_INCOMING);
+        startService(serviceIntent);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver,
+                new IntentFilter(ACTION_NOTIFY));
+        mHistoryView.setText("");
+        Intent serviceIntent = new Intent(ACTION_GET_CONVERSATION);
+        startService(serviceIntent);
+
+    }
+
+    @Override
+    protected void onPause() {
+        LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
+        super.onPause();
+    }
+
+    private void processMessage(Intent intent) {
+        String text = intent.getStringExtra(EXTRA_MESSAGE);
+        if (!TextUtils.isEmpty(text)) {
+            mHistoryView.append("\n" + text);
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        super.onCreateOptionsMenu(menu);
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.action_stop_service:
+                stopService(new Intent(this, ResponderService.class));
+                finish();
+                break;
+        }
+        return true;
+    }
+}
diff --git a/samples/browseable/ElizaChat/Application/src/com.example.android.elizachat/ResponderService.java b/samples/browseable/ElizaChat/Application/src/com.example.android.elizachat/ResponderService.java
new file mode 100644
index 0000000..6d6cd9a
--- /dev/null
+++ b/samples/browseable/ElizaChat/Application/src/com.example.android.elizachat/ResponderService.java
@@ -0,0 +1,148 @@
+/*
+ * 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.elizachat;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Intent;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.RemoteInput;
+import android.support.v4.content.LocalBroadcastManager;
+import android.support.v4.app.NotificationManagerCompat;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * A service that runs in the background and provides responses to the incoming messages from the
+ * wearable. It also keeps a record of the chat session history, which it can provide upon request.
+ */
+public class ResponderService extends Service {
+
+    public static final String ACTION_INCOMING = "com.example.android.elizachat.INCOMING";
+
+    public static final String ACTION_RESPONSE = "com.example.android.elizachat.REPLY";
+
+    public static final String EXTRA_REPLY = "reply";
+
+    private static final String TAG = "ResponderService";
+
+    private ElizaResponder mResponder;
+
+    private String mLastResponse = null;
+
+    private StringBuffer mCompleteConversation = new StringBuffer();
+
+    private LocalBroadcastManager mBroadcastManager;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "Chat Service started");
+        }
+        mResponder = new ElizaResponder();
+        mBroadcastManager = LocalBroadcastManager.getInstance(this);
+        processIncoming(null);
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        if (null == intent || null == intent.getAction()) {
+            return Service.START_STICKY;
+        }
+        String action = intent.getAction();
+        if (action.equals(ACTION_RESPONSE)) {
+            Bundle remoteInputResults = RemoteInput.getResultsFromIntent(intent);
+            CharSequence replyMessage = "";
+            if (remoteInputResults != null) {
+                replyMessage = remoteInputResults.getCharSequence(EXTRA_REPLY);
+            }
+            processIncoming(replyMessage.toString());
+        } else if (action.equals(MainActivity.ACTION_GET_CONVERSATION)) {
+            broadcastMessage(mCompleteConversation.toString());
+        }
+        return Service.START_STICKY;
+    }
+
+    private void showNotification() {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "Sent: " + mLastResponse);
+        }
+        NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
+                .setContentTitle(getString(R.string.eliza))
+                .setContentText(mLastResponse)
+                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.bg_eliza))
+                .setSmallIcon(R.drawable.bg_eliza)
+                .setPriority(NotificationCompat.PRIORITY_MIN);
+
+        Intent intent = new Intent(ACTION_RESPONSE);
+        PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent,
+                PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT);
+        Notification notification = builder
+                .extend(new NotificationCompat.WearableExtender()
+                        .addAction(new NotificationCompat.Action.Builder(
+                                R.drawable.ic_full_reply, getString(R.string.reply), pendingIntent)
+                                .addRemoteInput(new RemoteInput.Builder(EXTRA_REPLY)
+                                        .setLabel(getString(R.string.reply))
+                                        .build())
+                                .build()))
+                .build();
+        NotificationManagerCompat.from(this).notify(0, notification);
+    }
+
+    private void processIncoming(String text) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "Received: " + text);
+        }
+        mLastResponse = mResponder.elzTalk(text);
+        String line = TextUtils.isEmpty(text) ? mLastResponse : text + "\n" + mLastResponse;
+
+        // Send a new line of conversation to update the Activity, unless the incoming text was
+        // empty.
+        if (!TextUtils.isEmpty(text)) {
+            broadcastMessage(line);
+        }
+        NotificationManagerCompat.from(this).cancelAll();
+        showNotification();
+        mCompleteConversation.append("\n" + line);
+    }
+
+    private void broadcastMessage(String message) {
+        Intent intent = new Intent(MainActivity.ACTION_NOTIFY);
+        intent.putExtra(MainActivity.EXTRA_MESSAGE, message);
+        mBroadcastManager.sendBroadcast(intent);
+    }
+
+    @Override
+    public void onDestroy() {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "Chat Service stopped");
+        }
+        NotificationManagerCompat.from(this).cancel(0);
+        mBroadcastManager = null;
+        super.onDestroy();
+    }
+}
diff --git a/samples/browseable/ElizaChat/Shared/AndroidManifest.xml b/samples/browseable/ElizaChat/Shared/AndroidManifest.xml
new file mode 100644
index 0000000..9c02d59
--- /dev/null
+++ b/samples/browseable/ElizaChat/Shared/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.elizachat.common">
+
+    <application android:allowBackup="true"
+        android:label="@string/app_name">
+    </application>
+
+</manifest>
diff --git a/samples/browseable/ElizaChat/Shared/res/values/strings.xml b/samples/browseable/ElizaChat/Shared/res/values/strings.xml
new file mode 100644
index 0000000..0f2bb90
--- /dev/null
+++ b/samples/browseable/ElizaChat/Shared/res/values/strings.xml
@@ -0,0 +1,18 @@
+<?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">Shared</string>
+</resources>
diff --git a/samples/browseable/ElizaChat/_index.jd b/samples/browseable/ElizaChat/_index.jd
new file mode 100644
index 0000000..a88371c
--- /dev/null
+++ b/samples/browseable/ElizaChat/_index.jd
@@ -0,0 +1,12 @@
+page.tags="ElizaChat"
+sample.group=Wearable
+@jd:body
+
+<p>
+            
+            This sample is a phone application that provides a chat experience in which users can respond to
+            messages with a quick voice response. New messages create a notification with a "Reply" action.
+            The notification is bridged from phone to wearable, and selecting the "Reply" action on the
+            wearable opens the voice transcription UI allowing the user to speak a response.
+            
+        </p>