Merge "SDK: Windows USB driver rev 8."
diff --git a/build/Android.mk b/build/Android.mk
index 028b2f5..6d798de 100644
--- a/build/Android.mk
+++ b/build/Android.mk
@@ -122,6 +122,7 @@
     android-support-v4 \
     android-support-v7-gridlayout \
     android-support-v7-appcompat \
+    android-support-v7-mediarouter \
     android-support-v13
 
 $(foreach lib, $(ANDROID_SUPPORT_LIBRARIES), $(eval $(call _package_sdk_library,$(lib))))
diff --git a/build/sdk.atree b/build/sdk.atree
index 2ef1144..6cb6967 100644
--- a/build/sdk.atree
+++ b/build/sdk.atree
@@ -270,6 +270,17 @@
 frameworks/support/v7/appcompat/src/.readme                                                       extras/android/support/v7/appcompat/src/.readme
 ${OUT_DIR}/target/common/obj/PACKAGING/android-support-v7-appcompat_intermediates/android-support-v7-appcompat.jar    extras/android/support/v7/appcompat/libs/android-support-v7-appcompat.jar
 
+frameworks/support/v7/mediarouter/README.txt                                                       extras/android/support/v7/mediarouter/README.txt
+frameworks/support/v7/mediarouter/.project                                                         extras/android/support/v7/mediarouter/.project
+frameworks/support/v7/mediarouter/.classpath                                                       extras/android/support/v7/mediarouter/.classpath
+frameworks/support/v7/mediarouter/AndroidManifest.xml                                              extras/android/support/v7/mediarouter/AndroidManifest.xml
+frameworks/support/v7/mediarouter/project.properties                                               extras/android/support/v7/mediarouter/project.properties
+frameworks/support/v7/mediarouter/res                                                              extras/android/support/v7/mediarouter/res
+frameworks/support/v7/mediarouter/src/.readme                                                      extras/android/support/v7/mediarouter/src/.readme
+${OUT_DIR}/target/common/obj/PACKAGING/android-support-v7-mediarouter_intermediates/android-support-v7-mediarouter.jar    extras/android/support/v7/mediarouter/libs/android-support-v7-mediarouter.jar
+
+development/samples/Support7Demos                                                                 extras/android/support/samples/Support7Demos
+
 ##############################################################################
 # Tests Component
 ##############################################################################
diff --git a/ndk/platforms/android-18/samples/gles3jni/README b/ndk/platforms/android-18/samples/gles3jni/README
index 517eec3..2250e21 100644
--- a/ndk/platforms/android-18/samples/gles3jni/README
+++ b/ndk/platforms/android-18/samples/gles3jni/README
@@ -30,4 +30,4 @@
 [*1] The only dependency on API level 11 is the call to
      setEGLContextClientVersion in GLES3JNIView. With a custom
      EGLConfigChooser and EGLContextFactory the sample would be compatible
-     with older API levels.
\ No newline at end of file
+     with older API levels.
diff --git a/ndk/platforms/android-18/samples/gles3jni/jni/gl3stub.c b/ndk/platforms/android-18/samples/gles3jni/jni/gl3stub.c
index b579f23..19b78e7 100644
--- a/ndk/platforms/android-18/samples/gles3jni/jni/gl3stub.c
+++ b/ndk/platforms/android-18/samples/gles3jni/jni/gl3stub.c
@@ -15,120 +15,114 @@
  */
 
 #include "gl3stub.h"
-#include <dlfcn.h>
-
 
 GLboolean gl3stubInit() {
-    void* so = dlopen("libGLESv3.so", RTLD_NOW | RTLD_GLOBAL);
-    if (!so)
-        return GL_FALSE;
-
-    #define DLSYM(s) s = dlsym(so, #s)
-    DLSYM(glReadBuffer);
-    DLSYM(glDrawRangeElements);
-    DLSYM(glTexImage3D);
-    DLSYM(glTexSubImage3D);
-    DLSYM(glCopyTexSubImage3D);
-    DLSYM(glCompressedTexImage3D);
-    DLSYM(glCompressedTexSubImage3D);
-    DLSYM(glGenQueries);
-    DLSYM(glDeleteQueries);
-    DLSYM(glIsQuery);
-    DLSYM(glBeginQuery);
-    DLSYM(glEndQuery);
-    DLSYM(glGetQueryiv);
-    DLSYM(glGetQueryObjectuiv);
-    DLSYM(glUnmapBuffer);
-    DLSYM(glGetBufferPointerv);
-    DLSYM(glDrawBuffers);
-    DLSYM(glUniformMatrix2x3fv);
-    DLSYM(glUniformMatrix3x2fv);
-    DLSYM(glUniformMatrix2x4fv);
-    DLSYM(glUniformMatrix4x2fv);
-    DLSYM(glUniformMatrix3x4fv);
-    DLSYM(glUniformMatrix4x3fv);
-    DLSYM(glBlitFramebuffer);
-    DLSYM(glRenderbufferStorageMultisample);
-    DLSYM(glFramebufferTextureLayer);
-    DLSYM(glMapBufferRange);
-    DLSYM(glFlushMappedBufferRange);
-    DLSYM(glBindVertexArray);
-    DLSYM(glDeleteVertexArrays);
-    DLSYM(glGenVertexArrays);
-    DLSYM(glIsVertexArray);
-    DLSYM(glGetIntegeri_v);
-    DLSYM(glBeginTransformFeedback);
-    DLSYM(glEndTransformFeedback);
-    DLSYM(glBindBufferRange);
-    DLSYM(glBindBufferBase);
-    DLSYM(glTransformFeedbackVaryings);
-    DLSYM(glGetTransformFeedbackVarying);
-    DLSYM(glVertexAttribIPointer);
-    DLSYM(glGetVertexAttribIiv);
-    DLSYM(glGetVertexAttribIuiv);
-    DLSYM(glVertexAttribI4i);
-    DLSYM(glVertexAttribI4ui);
-    DLSYM(glVertexAttribI4iv);
-    DLSYM(glVertexAttribI4uiv);
-    DLSYM(glGetUniformuiv);
-    DLSYM(glGetFragDataLocation);
-    DLSYM(glUniform1ui);
-    DLSYM(glUniform2ui);
-    DLSYM(glUniform3ui);
-    DLSYM(glUniform4ui);
-    DLSYM(glUniform1uiv);
-    DLSYM(glUniform2uiv);
-    DLSYM(glUniform3uiv);
-    DLSYM(glUniform4uiv);
-    DLSYM(glClearBufferiv);
-    DLSYM(glClearBufferuiv);
-    DLSYM(glClearBufferfv);
-    DLSYM(glClearBufferfi);
-    DLSYM(glGetStringi);
-    DLSYM(glCopyBufferSubData);
-    DLSYM(glGetUniformIndices);
-    DLSYM(glGetActiveUniformsiv);
-    DLSYM(glGetUniformBlockIndex);
-    DLSYM(glGetActiveUniformBlockiv);
-    DLSYM(glGetActiveUniformBlockName);
-    DLSYM(glUniformBlockBinding);
-    DLSYM(glDrawArraysInstanced);
-    DLSYM(glDrawElementsInstanced);
-    DLSYM(glFenceSync);
-    DLSYM(glIsSync);
-    DLSYM(glDeleteSync);
-    DLSYM(glClientWaitSync);
-    DLSYM(glWaitSync);
-    DLSYM(glGetInteger64v);
-    DLSYM(glGetSynciv);
-    DLSYM(glGetInteger64i_v);
-    DLSYM(glGetBufferParameteri64v);
-    DLSYM(glGenSamplers);
-    DLSYM(glDeleteSamplers);
-    DLSYM(glIsSampler);
-    DLSYM(glBindSampler);
-    DLSYM(glSamplerParameteri);
-    DLSYM(glSamplerParameteriv);
-    DLSYM(glSamplerParameterf);
-    DLSYM(glSamplerParameterfv);
-    DLSYM(glGetSamplerParameteriv);
-    DLSYM(glGetSamplerParameterfv);
-    DLSYM(glVertexAttribDivisor);
-    DLSYM(glBindTransformFeedback);
-    DLSYM(glDeleteTransformFeedbacks);
-    DLSYM(glGenTransformFeedbacks);
-    DLSYM(glIsTransformFeedback);
-    DLSYM(glPauseTransformFeedback);
-    DLSYM(glResumeTransformFeedback);
-    DLSYM(glGetProgramBinary);
-    DLSYM(glProgramBinary);
-    DLSYM(glProgramParameteri);
-    DLSYM(glInvalidateFramebuffer);
-    DLSYM(glInvalidateSubFramebuffer);
-    DLSYM(glTexStorage2D);
-    DLSYM(glTexStorage3D);
-    DLSYM(glGetInternalformativ);
-    #undef DLSYM
+    #define FIND_PROC(s) s = (void*)eglGetProcAddress(#s)
+    FIND_PROC(glReadBuffer);
+    FIND_PROC(glDrawRangeElements);
+    FIND_PROC(glTexImage3D);
+    FIND_PROC(glTexSubImage3D);
+    FIND_PROC(glCopyTexSubImage3D);
+    FIND_PROC(glCompressedTexImage3D);
+    FIND_PROC(glCompressedTexSubImage3D);
+    FIND_PROC(glGenQueries);
+    FIND_PROC(glDeleteQueries);
+    FIND_PROC(glIsQuery);
+    FIND_PROC(glBeginQuery);
+    FIND_PROC(glEndQuery);
+    FIND_PROC(glGetQueryiv);
+    FIND_PROC(glGetQueryObjectuiv);
+    FIND_PROC(glUnmapBuffer);
+    FIND_PROC(glGetBufferPointerv);
+    FIND_PROC(glDrawBuffers);
+    FIND_PROC(glUniformMatrix2x3fv);
+    FIND_PROC(glUniformMatrix3x2fv);
+    FIND_PROC(glUniformMatrix2x4fv);
+    FIND_PROC(glUniformMatrix4x2fv);
+    FIND_PROC(glUniformMatrix3x4fv);
+    FIND_PROC(glUniformMatrix4x3fv);
+    FIND_PROC(glBlitFramebuffer);
+    FIND_PROC(glRenderbufferStorageMultisample);
+    FIND_PROC(glFramebufferTextureLayer);
+    FIND_PROC(glMapBufferRange);
+    FIND_PROC(glFlushMappedBufferRange);
+    FIND_PROC(glBindVertexArray);
+    FIND_PROC(glDeleteVertexArrays);
+    FIND_PROC(glGenVertexArrays);
+    FIND_PROC(glIsVertexArray);
+    FIND_PROC(glGetIntegeri_v);
+    FIND_PROC(glBeginTransformFeedback);
+    FIND_PROC(glEndTransformFeedback);
+    FIND_PROC(glBindBufferRange);
+    FIND_PROC(glBindBufferBase);
+    FIND_PROC(glTransformFeedbackVaryings);
+    FIND_PROC(glGetTransformFeedbackVarying);
+    FIND_PROC(glVertexAttribIPointer);
+    FIND_PROC(glGetVertexAttribIiv);
+    FIND_PROC(glGetVertexAttribIuiv);
+    FIND_PROC(glVertexAttribI4i);
+    FIND_PROC(glVertexAttribI4ui);
+    FIND_PROC(glVertexAttribI4iv);
+    FIND_PROC(glVertexAttribI4uiv);
+    FIND_PROC(glGetUniformuiv);
+    FIND_PROC(glGetFragDataLocation);
+    FIND_PROC(glUniform1ui);
+    FIND_PROC(glUniform2ui);
+    FIND_PROC(glUniform3ui);
+    FIND_PROC(glUniform4ui);
+    FIND_PROC(glUniform1uiv);
+    FIND_PROC(glUniform2uiv);
+    FIND_PROC(glUniform3uiv);
+    FIND_PROC(glUniform4uiv);
+    FIND_PROC(glClearBufferiv);
+    FIND_PROC(glClearBufferuiv);
+    FIND_PROC(glClearBufferfv);
+    FIND_PROC(glClearBufferfi);
+    FIND_PROC(glGetStringi);
+    FIND_PROC(glCopyBufferSubData);
+    FIND_PROC(glGetUniformIndices);
+    FIND_PROC(glGetActiveUniformsiv);
+    FIND_PROC(glGetUniformBlockIndex);
+    FIND_PROC(glGetActiveUniformBlockiv);
+    FIND_PROC(glGetActiveUniformBlockName);
+    FIND_PROC(glUniformBlockBinding);
+    FIND_PROC(glDrawArraysInstanced);
+    FIND_PROC(glDrawElementsInstanced);
+    FIND_PROC(glFenceSync);
+    FIND_PROC(glIsSync);
+    FIND_PROC(glDeleteSync);
+    FIND_PROC(glClientWaitSync);
+    FIND_PROC(glWaitSync);
+    FIND_PROC(glGetInteger64v);
+    FIND_PROC(glGetSynciv);
+    FIND_PROC(glGetInteger64i_v);
+    FIND_PROC(glGetBufferParameteri64v);
+    FIND_PROC(glGenSamplers);
+    FIND_PROC(glDeleteSamplers);
+    FIND_PROC(glIsSampler);
+    FIND_PROC(glBindSampler);
+    FIND_PROC(glSamplerParameteri);
+    FIND_PROC(glSamplerParameteriv);
+    FIND_PROC(glSamplerParameterf);
+    FIND_PROC(glSamplerParameterfv);
+    FIND_PROC(glGetSamplerParameteriv);
+    FIND_PROC(glGetSamplerParameterfv);
+    FIND_PROC(glVertexAttribDivisor);
+    FIND_PROC(glBindTransformFeedback);
+    FIND_PROC(glDeleteTransformFeedbacks);
+    FIND_PROC(glGenTransformFeedbacks);
+    FIND_PROC(glIsTransformFeedback);
+    FIND_PROC(glPauseTransformFeedback);
+    FIND_PROC(glResumeTransformFeedback);
+    FIND_PROC(glGetProgramBinary);
+    FIND_PROC(glProgramBinary);
+    FIND_PROC(glProgramParameteri);
+    FIND_PROC(glInvalidateFramebuffer);
+    FIND_PROC(glInvalidateSubFramebuffer);
+    FIND_PROC(glTexStorage2D);
+    FIND_PROC(glTexStorage3D);
+    FIND_PROC(glGetInternalformativ);
+    #undef FIND_PROC
 
     if (!glReadBuffer ||
         !glDrawRangeElements ||
@@ -235,7 +229,6 @@
         !glTexStorage3D ||
         !glGetInternalformativ)
     {
-        dlclose(so);
         return GL_FALSE;
     }
 
diff --git a/samples/training/testingfun/app/AndroidManifest.xml b/samples/training/testingfun/app/AndroidManifest.xml
new file mode 100644
index 0000000..a71247a
--- /dev/null
+++ b/samples/training/testingfun/app/AndroidManifest.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  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.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.testingfun"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk
+        android:minSdkVersion="8"
+        android:targetSdkVersion="17" />
+    <application
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/AppTheme"
+        android:allowBackup="false">
+
+        <activity
+            android:name=".lesson2.MyFirstTestActivity"
+            android:label="@string/my_first_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".lesson3.ClickFunActivity"
+            android:label="@string/click_fun">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".lesson4.LaunchActivity"
+            android:label="@string/launch_next">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".lesson4.NextActivity"
+            android:label="@string/next_activity" />
+        <activity
+            android:name=".lesson5.SenderActivity"
+            android:label="@string/sender_activity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".lesson5.ReceiverActivity"
+            android:label="@string/receiver_activity" />
+    </application>
+</manifest>
diff --git a/samples/training/testingfun/app/build.gradle b/samples/training/testingfun/app/build.gradle
new file mode 100644
index 0000000..c68484f
--- /dev/null
+++ b/samples/training/testingfun/app/build.gradle
@@ -0,0 +1,27 @@
+apply plugin: 'android'
+
+android {
+    compileSdkVersion 17
+    buildToolsVersion "17.0.0"
+
+    defaultConfig {
+        minSdkVersion 8
+    }
+
+    android {
+        sourceSets {
+            main {
+                manifest.srcFile 'AndroidManifest.xml'
+                java.srcDirs = ['src']
+                resources.srcDirs = ['src']
+                aild.srcDirs = ['src']
+                renderscript.srcDirs = ['src']
+                res.srcDirs = ['res']
+                assets.srcDirs = ['assets']
+            }
+
+            instrumentTest.setRoot('tests')
+            instrumentTest.java.srcDirs = ['tests/src']
+        }
+    }
+}
\ No newline at end of file
diff --git a/samples/training/testingfun/app/project.properties b/samples/training/testingfun/app/project.properties
new file mode 100644
index 0000000..a3ee5ab
--- /dev/null
+++ b/samples/training/testingfun/app/project.properties
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-17
diff --git a/samples/training/testingfun/app/res/drawable-hdpi/ic_launcher.png b/samples/training/testingfun/app/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..136343e
--- /dev/null
+++ b/samples/training/testingfun/app/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/testingfun/app/res/drawable-mdpi/ic_launcher.png b/samples/training/testingfun/app/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..6837266
--- /dev/null
+++ b/samples/training/testingfun/app/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/testingfun/app/res/drawable-xhdpi/ic_launcher.png b/samples/training/testingfun/app/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..e88e975
--- /dev/null
+++ b/samples/training/testingfun/app/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/testingfun/app/res/drawable-xxhdpi/ic_launcher.png b/samples/training/testingfun/app/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..ac31a90
--- /dev/null
+++ b/samples/training/testingfun/app/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/testingfun/app/res/layout/activity_click_fun.xml b/samples/training/testingfun/app/res/layout/activity_click_fun.xml
new file mode 100644
index 0000000..c960c3b
--- /dev/null
+++ b/samples/training/testingfun/app/res/layout/activity_click_fun.xml
@@ -0,0 +1,32 @@
+<!--
+  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.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <Button
+        android:id="@+id/launch_next_activity_button"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/label_click_me" />
+
+    <TextView
+        android:id="@+id/info_text_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:visibility="gone" />
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/training/testingfun/app/res/layout/activity_launch_next.xml b/samples/training/testingfun/app/res/layout/activity_launch_next.xml
new file mode 100644
index 0000000..cfd0114
--- /dev/null
+++ b/samples/training/testingfun/app/res/layout/activity_launch_next.xml
@@ -0,0 +1,25 @@
+<!--
+  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.
+  -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <Button
+        android:id="@+id/launch_next_activity_button"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/label_launch_next" />
+</merge>
\ No newline at end of file
diff --git a/samples/training/testingfun/app/res/layout/activity_my_first_test.xml b/samples/training/testingfun/app/res/layout/activity_my_first_test.xml
new file mode 100644
index 0000000..3499bc7
--- /dev/null
+++ b/samples/training/testingfun/app/res/layout/activity_my_first_test.xml
@@ -0,0 +1,27 @@
+<!--
+  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.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/my_first_test_text_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/my_first_test" />
+</LinearLayout>
+
diff --git a/samples/training/testingfun/app/res/layout/activity_next.xml b/samples/training/testingfun/app/res/layout/activity_next.xml
new file mode 100644
index 0000000..92f30f7
--- /dev/null
+++ b/samples/training/testingfun/app/res/layout/activity_next.xml
@@ -0,0 +1,25 @@
+<!--
+  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.
+  -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/next_activity_info_text_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+</merge>
\ No newline at end of file
diff --git a/samples/training/testingfun/app/res/layout/activity_receiver.xml b/samples/training/testingfun/app/res/layout/activity_receiver.xml
new file mode 100644
index 0000000..e93d16b
--- /dev/null
+++ b/samples/training/testingfun/app/res/layout/activity_receiver.xml
@@ -0,0 +1,25 @@
+<!--
+  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.
+  -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/received_message_text_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+</merge>
\ No newline at end of file
diff --git a/samples/training/testingfun/app/res/layout/activity_sender.xml b/samples/training/testingfun/app/res/layout/activity_sender.xml
new file mode 100644
index 0000000..e18f4c4
--- /dev/null
+++ b/samples/training/testingfun/app/res/layout/activity_sender.xml
@@ -0,0 +1,33 @@
+<!--
+  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.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <EditText
+        android:id="@+id/message_input_edit_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:hint="@string/message_input_hint_edit_text" />
+
+    <Button
+        android:id="@+id/send_message_button"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/label_send_message" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/training/testingfun/app/res/values-sw720dp-land/dimens.xml b/samples/training/testingfun/app/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..3201e93
--- /dev/null
+++ b/samples/training/testingfun/app/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,18 @@
+<!--
+  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.
+  -->
+<resources>
+    <dimen name="activity_horizontal_margin">128dp</dimen>
+</resources>
diff --git a/samples/training/testingfun/app/res/values-v11/styles.xml b/samples/training/testingfun/app/res/values-v11/styles.xml
new file mode 100644
index 0000000..90ff160
--- /dev/null
+++ b/samples/training/testingfun/app/res/values-v11/styles.xml
@@ -0,0 +1,18 @@
+<!--
+  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.
+  -->
+<resources>
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar" />
+</resources>
diff --git a/samples/training/testingfun/app/res/values-v14/styles.xml b/samples/training/testingfun/app/res/values-v14/styles.xml
new file mode 100644
index 0000000..90ff160
--- /dev/null
+++ b/samples/training/testingfun/app/res/values-v14/styles.xml
@@ -0,0 +1,18 @@
+<!--
+  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.
+  -->
+<resources>
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar" />
+</resources>
diff --git a/samples/training/testingfun/app/res/values/dimens.xml b/samples/training/testingfun/app/res/values/dimens.xml
new file mode 100644
index 0000000..e96acda
--- /dev/null
+++ b/samples/training/testingfun/app/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<!--
+  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.
+  -->
+<resources>
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>
diff --git a/samples/training/testingfun/app/res/values/strings.xml b/samples/training/testingfun/app/res/values/strings.xml
new file mode 100644
index 0000000..1fc3bc0
--- /dev/null
+++ b/samples/training/testingfun/app/res/values/strings.xml
@@ -0,0 +1,34 @@
+<!--
+  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.
+  -->
+<resources>
+    <string name="app_name">Android Testing Fun</string>
+
+    <string name="my_first_test">My First Test</string>
+
+    <string name="click_fun">Click Fun Test</string>
+    <string name="label_click_me">Click me</string>
+
+    <string name="launch_next">Launch Activity</string>
+    <string name="next_activity">Next Activity</string>
+
+    <string name="sender_activity">Sender Activity</string>
+    <string name="receiver_activity">Receiver Activity</string>
+
+    <string name="info_text">Button clicked!</string>
+    <string name="label_launch_next">Launch Next</string>
+    <string name="label_send_message">Send</string>
+    <string name="message_input_hint_edit_text">Enter a message</string>
+</resources>
diff --git a/samples/training/testingfun/app/res/values/styles.xml b/samples/training/testingfun/app/res/values/styles.xml
new file mode 100644
index 0000000..fa3d1bd
--- /dev/null
+++ b/samples/training/testingfun/app/res/values/styles.xml
@@ -0,0 +1,20 @@
+<!--
+  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.
+  -->
+<resources>
+    <style name="AppBaseTheme" parent="android:Theme.Light" />
+
+    <style name="AppTheme" parent="AppBaseTheme" />
+</resources>
diff --git a/samples/training/testingfun/app/src/com/example/android/testingfun/lesson2/MyFirstTestActivity.java b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson2/MyFirstTestActivity.java
new file mode 100644
index 0000000..db977cf
--- /dev/null
+++ b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson2/MyFirstTestActivity.java
@@ -0,0 +1,36 @@
+/*
+ * 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.testingfun.lesson2;
+
+import com.example.android.testingfun.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Activity with a TextView that contains a String label.
+ */
+public class MyFirstTestActivity extends Activity {
+
+    /**
+     * Called when the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_my_first_test);
+    }
+}
diff --git a/samples/training/testingfun/app/src/com/example/android/testingfun/lesson3/ClickFunActivity.java b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson3/ClickFunActivity.java
new file mode 100644
index 0000000..09db694
--- /dev/null
+++ b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson3/ClickFunActivity.java
@@ -0,0 +1,47 @@
+/*
+ * 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.testingfun.lesson3;
+
+import com.example.android.testingfun.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ * Activity which shows a "click me" button. When the button is clicked, a TextView is shown below
+ * the button.
+ */
+public class ClickFunActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_click_fun);
+
+        final TextView infoTextView = (TextView) findViewById(R.id.info_text_view);
+        final Button clickMeButton = (Button) findViewById(R.id.launch_next_activity_button);
+        clickMeButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                infoTextView.setVisibility(View.VISIBLE);
+                infoTextView.setText(getString(R.string.info_text));
+            }
+        });
+    }
+}
\ No newline at end of file
diff --git a/samples/training/testingfun/app/src/com/example/android/testingfun/lesson4/LaunchActivity.java b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson4/LaunchActivity.java
new file mode 100644
index 0000000..6459a56
--- /dev/null
+++ b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson4/LaunchActivity.java
@@ -0,0 +1,47 @@
+/*
+ * 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.testingfun.lesson4;
+
+import com.example.android.testingfun.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+
+/**
+ * Launches NextActivity and passes a payload in the Bundle.
+ */
+public class LaunchActivity extends Activity {
+
+    /**
+     * The payload that is passed as Intent data to NextActivity.
+     */
+    public final static String STRING_PAYLOAD = "Started from LaunchActivity";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_launch_next);
+        Button launchNextButton = (Button) findViewById(R.id.launch_next_activity_button);
+        launchNextButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                startActivity(NextActivity.makeIntent(LaunchActivity.this, STRING_PAYLOAD));
+            }
+        });
+    }
+}
diff --git a/samples/training/testingfun/app/src/com/example/android/testingfun/lesson4/NextActivity.java b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson4/NextActivity.java
new file mode 100644
index 0000000..68965c2
--- /dev/null
+++ b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson4/NextActivity.java
@@ -0,0 +1,61 @@
+/*
+ * 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.testingfun.lesson4;
+
+import com.example.android.testingfun.R;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.TextView;
+
+/**
+ * This activity is started from LaunchActivity. It reads the payload from the given bundle and
+ * displays it using a TextView.
+ */
+public class NextActivity extends Activity {
+
+    /**
+     * Extras key for the payload.
+     */
+    public final static String EXTRAS_PAYLOAD_KEY
+            = "com.example.android.testingfun.lesson4.EXTRAS_PAYLOAD_KEY";
+
+    /**
+     * Factory method to create a launch Intent for this activity.
+     *
+     * @param context the context that intent should be bound to
+     * @param payload the payload data that should be added for this intent
+     * @return a configured intent to launch this activity with a String payload.
+     */
+    public static Intent makeIntent(Context context, String payload) {
+        return new Intent(context, NextActivity.class).putExtra(EXTRAS_PAYLOAD_KEY, payload);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_next);
+
+        final String stringPayload = getIntent().getStringExtra(EXTRAS_PAYLOAD_KEY);
+
+        if (stringPayload != null) {
+            ((TextView) findViewById(R.id.next_activity_info_text_view)).setText(stringPayload);
+        }
+
+    }
+}
diff --git a/samples/training/testingfun/app/src/com/example/android/testingfun/lesson5/ReceiverActivity.java b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson5/ReceiverActivity.java
new file mode 100644
index 0000000..2bc401d
--- /dev/null
+++ b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson5/ReceiverActivity.java
@@ -0,0 +1,61 @@
+/*
+ * 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.testingfun.lesson5;
+
+import com.example.android.testingfun.R;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.widget.TextView;
+
+/**
+ * Receives a message from SenderActivity and displays the message.
+ */
+public class ReceiverActivity extends Activity {
+
+    /**
+     * The extra key that is used to identify the message in the Intents data bundle
+     */
+    private static final String EXTRA_SENDER_MESSAGE_TEXT
+            = "com.example.android.testingfun.lesson5.extra.sender.message.text";
+
+    /**
+     * Factory method to create an launch intent for this activity.
+     *
+     * @param context the context to this intent should be bound to
+     * @param message the message data that should be added to this intent
+     * @return a configured intent to launch this activity with a given message
+     */
+    public static Intent makeIntent(Context context, CharSequence message) {
+        return new Intent(context, ReceiverActivity.class)
+                .putExtra(EXTRA_SENDER_MESSAGE_TEXT, message);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_receiver);
+        final CharSequence senderMessage = getIntent()
+                .getCharSequenceExtra(EXTRA_SENDER_MESSAGE_TEXT);
+        final TextView receiverTextView = (TextView) findViewById(R.id.received_message_text_view);
+        if (!TextUtils.isEmpty(senderMessage)) {
+            receiverTextView.setText(senderMessage);
+        }
+    }
+}
diff --git a/samples/training/testingfun/app/src/com/example/android/testingfun/lesson5/SenderActivity.java b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson5/SenderActivity.java
new file mode 100644
index 0000000..495f1e6
--- /dev/null
+++ b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson5/SenderActivity.java
@@ -0,0 +1,47 @@
+/*
+ * 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.testingfun.lesson5;
+
+import com.example.android.testingfun.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+
+/**
+ * Sends a user generated message to the ReceiverActivity
+ */
+public class SenderActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_sender);
+        final Button sendMessageButton = (Button) findViewById(R.id.send_message_button);
+        final EditText messageInputEditText = (EditText) findViewById(R.id.message_input_edit_text);
+        sendMessageButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (messageInputEditText != null) {
+                    final CharSequence message = messageInputEditText.getText();
+                    startActivity(ReceiverActivity.makeIntent(SenderActivity.this, message));
+                }
+            }
+        });
+    }
+}
diff --git a/samples/training/testingfun/app/tests/AndroidManifest.xml b/samples/training/testingfun/app/tests/AndroidManifest.xml
new file mode 100644
index 0000000..13ce6ab
--- /dev/null
+++ b/samples/training/testingfun/app/tests/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  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 name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.testingfun.tests"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk
+        android:minSdkVersion="8"
+        android:targetSdkVersion="17" />
+
+    <!-- We add an application tag here just so that we can indicate that
+         this package needs to link against the android.test library,
+         which is needed when building test cases. -->
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <!--
+    Specifies the instrumentation test runner used to run the tests.
+    -->
+    <instrumentation
+        android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="com.example.android.testingfun"
+        android:label="Tests for com.example.android.testingfun" />
+</manifest>
\ No newline at end of file
diff --git a/samples/training/testingfun/app/tests/project.properties b/samples/training/testingfun/app/tests/project.properties
new file mode 100644
index 0000000..a3ee5ab
--- /dev/null
+++ b/samples/training/testingfun/app/tests/project.properties
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-17
diff --git a/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson2/MyFirstTestActivityTest.java b/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson2/MyFirstTestActivityTest.java
new file mode 100644
index 0000000..ad18b55
--- /dev/null
+++ b/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson2/MyFirstTestActivityTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.testingfun.tests.lesson2;
+
+import com.example.android.testingfun.R;
+import com.example.android.testingfun.lesson2.MyFirstTestActivity;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.widget.TextView;
+
+/**
+ * Tests for MyFirstTestActivity.
+ */
+public class MyFirstTestActivityTest extends ActivityInstrumentationTestCase2<MyFirstTestActivity> {
+
+    private MyFirstTestActivity mFirstTestActivity;
+    private TextView mFirstTestText;
+
+    public MyFirstTestActivityTest() {
+        super(MyFirstTestActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // Starts the activity under test using the default Intent with:
+        // action = {@link Intent#ACTION_MAIN}
+        // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+        // All other fields are null or empty.
+        mFirstTestActivity = getActivity();
+        mFirstTestText = (TextView) mFirstTestActivity.findViewById(R.id.my_first_test_text_view);
+    }
+
+    /**
+     * Test if your test fixture has been set up correctly. You should always implement a test that
+     * checks the correct setup of your test fixture. If this tests fails all other tests are
+     * likely to fail as well.
+     */
+    public void testPreconditions() {
+        //Try to add a message to add context to your assertions. These messages will be shown if
+        //a tests fails and make it easy to understand why a test failed
+        assertNotNull("mFirstTestActivity is null", mFirstTestActivity);
+        assertNotNull("mFirstTestText is null", mFirstTestText);
+    }
+
+    /**
+     * Tests the correctness of the initial text.
+     */
+    public void testMyFirstTestTextView_labelText() {
+        //It is good practice to read the string from your resources in order to not break
+        //multiple tests when a string changes.
+        final String expected = mFirstTestActivity.getString(R.string.my_first_test);
+        final String actual = mFirstTestText.getText().toString();
+        assertEquals("mFirstTestText contains wrong text", expected, actual);
+    }
+}
\ No newline at end of file
diff --git a/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson3/ClickFunActivityTest.java b/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson3/ClickFunActivityTest.java
new file mode 100644
index 0000000..5d3d387
--- /dev/null
+++ b/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson3/ClickFunActivityTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.testingfun.tests.lesson3;
+
+
+import com.example.android.testingfun.R;
+import com.example.android.testingfun.lesson3.ClickFunActivity;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.TouchUtils;
+import android.test.ViewAsserts;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ * Tests for ClickFunActivity. Introduces touch mode, test size annotations and TouchUtils.
+ */
+public class ClickFunActivityTest extends ActivityInstrumentationTestCase2<ClickFunActivity> {
+    
+    private ClickFunActivity mClickFunActivity;
+    private Button mClickMeButton;
+    private TextView mInfoTextView;
+
+    public ClickFunActivityTest() {
+        super(ClickFunActivity.class);
+    }
+
+    /**
+     * Sets up the test fixture for this test case. This method is always called before every test
+     * run.
+     */
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        //Sets the initial touch mode for the Activity under test. This must be called before
+        //getActivity()
+        setActivityInitialTouchMode(true);
+
+        //Get a reference to the Activity under test, starting it if necessary.
+        mClickFunActivity = getActivity();
+
+        //Get references to all views
+        mClickMeButton = (Button) mClickFunActivity.findViewById(R.id.launch_next_activity_button);
+        mInfoTextView = (TextView) mClickFunActivity.findViewById(R.id.info_text_view);
+    }
+
+    /**
+     * Tests the preconditions of this test fixture.
+     */
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull("mClickFunActivity is null", mClickFunActivity);
+        assertNotNull("mClickMeButton is null", mClickMeButton);
+        assertNotNull("mInfoTextView is null", mInfoTextView);
+    }
+
+    @MediumTest
+    public void testClickMeButton_layout() {
+        //Retrieve the top-level window decor view
+        final View decorView = mClickFunActivity.getWindow().getDecorView();
+
+        //Verify that the mClickMeButton is on screen
+        ViewAsserts.assertOnScreen(decorView, mClickMeButton);
+
+        //Verify width and heights
+        final ViewGroup.LayoutParams layoutParams = mClickMeButton.getLayoutParams();
+        assertNotNull(layoutParams);
+        assertEquals(layoutParams.width, WindowManager.LayoutParams.MATCH_PARENT);
+        assertEquals(layoutParams.height, WindowManager.LayoutParams.WRAP_CONTENT);
+    }
+
+    @MediumTest
+    public void testClickMeButton_labelText() {
+        //Verify that mClickMeButton uses the correct string resource
+        final String expectedNextButtonText = mClickFunActivity.getString(R.string.label_click_me);
+        final String actualNextButtonText = mClickMeButton.getText().toString();
+        assertEquals(expectedNextButtonText, actualNextButtonText);
+    }
+
+    @MediumTest
+    public void testInfoTextView_layout() {
+        //Retrieve the top-level window decor view
+        final View decorView = mClickFunActivity.getWindow().getDecorView();
+
+        //Verify that the mInfoTextView is on screen and is not visible
+        ViewAsserts.assertOnScreen(decorView, mInfoTextView);
+        assertTrue(View.GONE == mInfoTextView.getVisibility());
+    }
+
+    @MediumTest
+    public void testInfoTextViewText_isEmpty() {
+        //Verify that the mInfoTextView is initialized with the correct default value
+        assertEquals("", mInfoTextView.getText());
+    }
+
+    @MediumTest
+    public void testClickMeButton_clickButtonAndExpectInfoText() {
+        String expectedInfoText = mClickFunActivity.getString(R.string.info_text);
+        //Perform a click on mClickMeButton
+        TouchUtils.clickView(this, mClickMeButton);
+        //Verify the that mClickMeButton was clicked. mInfoTextView is visible and contains
+        //the correct text.
+        assertTrue(View.VISIBLE == mInfoTextView.getVisibility());
+        assertEquals(expectedInfoText, mInfoTextView.getText());
+    }
+}
diff --git a/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson4/LaunchActivityTest.java b/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson4/LaunchActivityTest.java
new file mode 100644
index 0000000..27606eb
--- /dev/null
+++ b/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson4/LaunchActivityTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.testingfun.tests.lesson4;
+
+import com.example.android.testingfun.R;
+import com.example.android.testingfun.lesson4.LaunchActivity;
+import com.example.android.testingfun.lesson4.NextActivity;
+
+import android.content.Intent;
+import android.test.ActivityUnitTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.Button;
+
+/**
+ * Tests LaunchActivity in isolation from the system.
+ */
+public class LaunchActivityTest extends ActivityUnitTestCase<LaunchActivity> {
+
+    private LaunchActivity mLaunchActivity;
+    private Button mLaunchNextButton;
+
+    public LaunchActivityTest() {
+        super(LaunchActivity.class);
+    }
+
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        //Create an intent to launch target Activity
+        final Intent intent = new Intent(getInstrumentation().getTargetContext(),
+                LaunchActivity.class);
+
+        //Start the activity under test in isolation, without values for savedInstanceState and
+        //lastNonConfigurationInstance
+        mLaunchActivity = startActivity(intent, null, null);
+        mLaunchNextButton = (Button) mLaunchActivity.findViewById(R.id.launch_next_activity_button);
+    }
+
+    /**
+     * Tests the preconditions of this test fixture.
+     */
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull("mLaunchActivity is null", mLaunchActivity);
+        assertNotNull("mLaunchNextButton is null", mLaunchNextButton);
+    }
+
+
+    @MediumTest
+    public void testLaunchNextActivityButton_labelText() {
+        final String expectedButtonText = mLaunchActivity.getString(R.string.label_launch_next);
+        assertEquals("Unexpected button label text", expectedButtonText,
+                mLaunchNextButton.getText());
+    }
+
+    @MediumTest
+    public void testNextActivityWasLaunchedWithIntent() {
+
+        //Because this is an isolated ActivityUnitTestCase we have to directly click the
+        //button from code
+        mLaunchNextButton.performClick();
+
+        // Get the intent for the next started activity
+        final Intent launchIntent = getStartedActivityIntent();
+        //Verify the intent was not null.
+        assertNotNull("Intent was null", launchIntent);
+
+        final String payload = launchIntent.getStringExtra(NextActivity.EXTRAS_PAYLOAD_KEY);
+        //Verify that payload data was added to the intent
+        assertEquals("Payload is empty", LaunchActivity.STRING_PAYLOAD
+                , payload);
+    }
+}
diff --git a/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson5/SenderActivityTest.java b/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson5/SenderActivityTest.java
new file mode 100644
index 0000000..75bc302
--- /dev/null
+++ b/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson5/SenderActivityTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.testingfun.tests.lesson5;
+
+import com.example.android.testingfun.R;
+import com.example.android.testingfun.lesson5.ReceiverActivity;
+import com.example.android.testingfun.lesson5.SenderActivity;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.TouchUtils;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+
+/**
+ * Functional test across multiple Activities. Tests SenderActivity and ReceiverActivity. Introduces
+ * advanced Instrumentation testing practices as sending key events and interaction monitoring
+ * between Activities and the system.
+ */
+public class SenderActivityTest extends ActivityInstrumentationTestCase2<SenderActivity> {
+
+    private static final int TIMEOUT_IN_MS = 5000;
+    private static final String TEST_MESSAGE = "Hello Receiver";
+    private SenderActivity mSenderActivity;
+
+    public SenderActivityTest() {
+        super(SenderActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        setActivityInitialTouchMode(true);
+        mSenderActivity = getActivity();
+    }
+
+    /**
+     * Tests the preconditions of this test fixture.
+     */
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull("mSenderActivity is null", mSenderActivity);
+    }
+
+    @MediumTest
+    public void testSendMessageToReceiverActivity() {
+
+        //Because this functional test tests interaction across multiple components these views
+        //are part of the actual test method and not of the test fixture
+        final Button sendToReceiverButton = (Button) mSenderActivity
+                .findViewById(R.id.send_message_button);
+        final EditText senderMessageEditText = (EditText) mSenderActivity
+                .findViewById(R.id.message_input_edit_text);
+
+        //Create and add an ActivityMonitor to monitor interaction between the system and the
+        //ReceiverActivity
+        Instrumentation.ActivityMonitor receiverActivityMonitor = getInstrumentation()
+                .addMonitor(ReceiverActivity.class.getName(), null, false);
+
+        //Request focus on the EditText field. This must be done on the UiThread because
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                senderMessageEditText.requestFocus();
+            }
+        });
+        //Wait until all events from the MainHandler's queue are processed
+        getInstrumentation().waitForIdleSync();
+
+        //Send the text message
+        getInstrumentation().sendStringSync(TEST_MESSAGE);
+        getInstrumentation().waitForIdleSync();
+
+        //Click on the sendToReceiverButton to send the message to ReceiverActivity
+        TouchUtils.clickView(this, sendToReceiverButton);
+
+        //Wait until ReceiverActivity was launched and get a reference to it.
+        ReceiverActivity receiverActivity = (ReceiverActivity) receiverActivityMonitor
+                .waitForActivityWithTimeout(TIMEOUT_IN_MS);
+        //Verify that ReceiverActivity was started
+        assertNotNull("ReceiverActivity is null", receiverActivity);
+        assertEquals("Monitor for ReceiverActivity has not been called", 1,
+                receiverActivityMonitor.getHits());
+        assertEquals("Activity is of wrong type", ReceiverActivity.class,
+                receiverActivity.getClass());
+
+        //Read the message received by ReceiverActivity
+        final TextView receivedMessage = (TextView) receiverActivity
+                .findViewById(R.id.received_message_text_view);
+        //Verify that received message is correct
+        assertNotNull(receivedMessage);
+        assertEquals("Wrong received message", TEST_MESSAGE, receivedMessage.getText().toString());
+
+        //Unregister monitor for ReceiverActivity
+        getInstrumentation().removeMonitor(receiverActivityMonitor);
+    }
+}
\ No newline at end of file
diff --git a/samples/training/testingfun/build.gradle b/samples/training/testingfun/build.gradle
new file mode 100644
index 0000000..06b6030
--- /dev/null
+++ b/samples/training/testingfun/build.gradle
@@ -0,0 +1,8 @@
+buildscript {
+    repositories {
+        mavenCentral()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:0.4.2'
+    }
+}
diff --git a/samples/training/testingfun/gradle/wrapper/gradle-wrapper.jar b/samples/training/testingfun/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8c0fb64
--- /dev/null
+++ b/samples/training/testingfun/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/samples/training/testingfun/gradle/wrapper/gradle-wrapper.properties b/samples/training/testingfun/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..5c22dec
--- /dev/null
+++ b/samples/training/testingfun/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.6-bin.zip
diff --git a/samples/training/testingfun/gradlew b/samples/training/testingfun/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/samples/training/testingfun/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/samples/training/testingfun/gradlew.bat b/samples/training/testingfun/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/samples/training/testingfun/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/samples/training/testingfun/settings.gradle b/samples/training/testingfun/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/samples/training/testingfun/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/sdk/build_tools_source.prop_template b/sdk/build_tools_source.prop_template
new file mode 100644
index 0000000..5d62307
--- /dev/null
+++ b/sdk/build_tools_source.prop_template
@@ -0,0 +1,3 @@
+Pkg.UserSrc=false
+Pkg.Revision=${PLATFORM_SDK_VERSION}.0.0
+
diff --git a/sdk/build_tools_source.properties b/sdk/build_tools_source.properties
deleted file mode 100644
index 3aa7a95..0000000
--- a/sdk/build_tools_source.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-Pkg.UserSrc=false
-Pkg.Revision=17.0.0
-
diff --git a/sdk/plat_tools_source.prop_template b/sdk/plat_tools_source.prop_template
new file mode 100644
index 0000000..5d62307
--- /dev/null
+++ b/sdk/plat_tools_source.prop_template
@@ -0,0 +1,3 @@
+Pkg.UserSrc=false
+Pkg.Revision=${PLATFORM_SDK_VERSION}.0.0
+
diff --git a/sdk/plat_tools_source.properties b/sdk/plat_tools_source.properties
deleted file mode 100644
index 3aa7a95..0000000
--- a/sdk/plat_tools_source.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-Pkg.UserSrc=false
-Pkg.Revision=17.0.0
-
diff --git a/sdk/support_source.properties b/sdk/support_source.prop_template
similarity index 82%
rename from sdk/support_source.properties
rename to sdk/support_source.prop_template
index fb611ec..ba7e6fb 100644
--- a/sdk/support_source.properties
+++ b/sdk/support_source.prop_template
@@ -1,5 +1,5 @@
 Pkg.UserSrc=false
-Pkg.Revision=11
+Pkg.Revision=${PLATFORM_SDK_VERSION}
 Extra.Vendor=android
 Extra.VendorId=android
 Extra.VendorDisplay=Android
diff --git a/testrunner/android_build.py b/testrunner/android_build.py
index a10d43b..cacd67e 100644
--- a/testrunner/android_build.py
+++ b/testrunner/android_build.py
@@ -48,6 +48,25 @@
   return root_path
 
 
+def GetHostOutDir():
+  """Returns the full pathname of out/host/arch of the Android development tree.
+
+  Assumes build environment has been properly configured by envsetup &
+  lunch/choosecombo.
+
+  Returns:
+    the absolute file path of the Android host output directory.
+  Raises:
+    AbortError: if Android host output directory could not be found.
+  """
+  host_out_path = os.getenv("ANDROID_HOST_OUT")
+  if host_out_path is None:
+    logger.Log("Error: ANDROID_HOST_OUT not defined. Please run "
+               "envsetup.sh and lunch/choosecombo")
+    raise errors.AbortError
+  return host_out_path
+
+
 def GetHostOsArch():
   """Identify the host os and arch.
 
@@ -72,10 +91,25 @@
   return (host_os, host_arch, "%s-%s" % (host_os, host_arch))
 
 
+def GetOutDir():
+  """Returns the full pathname of the "out" of the Android development tree.
+
+  Assumes build environment has been properly configured by envsetup &
+  lunch/choosecombo.
+
+  Returns:
+    the absolute file path of the Android build output directory.
+  """
+  root_path = os.getenv("OUT_DIR")
+  if root_path is None:
+    root_path = os.path.join(GetTop(), "out")
+  return root_path
+
+
 def GetHostBin():
   """Compute the full pathname to the host binary directory.
 
-  Typically $ANDROID_BUILD_TOP/out/host/linux-x86/bin.
+  Typically $ANDROID_HOST_OUT/bin.
 
   Assumes build environment has been properly configured by envsetup &
   lunch/choosecombo.
@@ -86,8 +120,7 @@
   Raises:
     AbortError: if Android host binary directory could not be found.
   """
-  (_, _, os_arch) = GetHostOsArch()
-  path = os.path.join(GetTop(), "out", "host", os_arch, "bin")
+  path = os.path.join(GetHostOutDir(), "bin")
   if not os.path.exists(path):
     logger.Log("Error: Host bin path could not be found %s" % path)
     raise errors.AbortError
@@ -139,7 +172,7 @@
 def GetHostLibraryPath():
   """Returns the full pathname to the host java library output directory.
 
-  Typically $ANDROID_BUILD_TOP/out/host/<host_os>/framework.
+  Typically $ANDROID_HOST_OUT/framework.
 
   Assumes build environment has been properly configured by envsetup &
   lunch/choosecombo.
@@ -150,8 +183,7 @@
   Raises:
     AbortError: if Android host java library directory could not be found.
   """
-  (_, _, os_arch) = GetHostOsArch()
-  path = os.path.join(GetTop(), "out", "host", os_arch, "framework")
+  path = os.path.join(GetHostOutDir(), "framework")
   if not os.path.exists(path):
     logger.Log("Error: Host library path could not be found %s" % path)
     raise errors.AbortError
diff --git a/testrunner/coverage/coverage.py b/testrunner/coverage/coverage.py
index 570527d..824f5c5 100755
--- a/testrunner/coverage/coverage.py
+++ b/testrunner/coverage/coverage.py
@@ -43,7 +43,7 @@
   _EMMA_JAR = os.path.join("external", "emma", "lib", "emma.jar")
   _TEST_COVERAGE_EXT = "ec"
   # root path of generated coverage report files, relative to Android build root
-  _COVERAGE_REPORT_PATH = os.path.join("out", "emma")
+  _COVERAGE_REPORT_PATH = "emma"
   _TARGET_DEF_FILE = "coverage_targets.xml"
   _CORE_TARGET_PATH = os.path.join("development", "testrunner",
                                    _TARGET_DEF_FILE)
@@ -53,12 +53,13 @@
                                      _TARGET_DEF_FILE)
 
   # path to root of target build intermediates
-  _TARGET_INTERMEDIATES_BASE_PATH = os.path.join("out", "target", "common",
+  _TARGET_INTERMEDIATES_BASE_PATH = os.path.join("target", "common",
                                                  "obj")
 
   def __init__(self, adb_interface):
     self._root_path = android_build.GetTop()
-    self._output_root_path = os.path.join(self._root_path,
+    self._out_path = android_build.GetOut()
+    self._output_root_path = os.path.join(self._out_path,
                                           self._COVERAGE_REPORT_PATH)
     self._emma_jar_path = os.path.join(self._root_path, self._EMMA_JAR)
     self._adb = adb_interface
@@ -78,7 +79,7 @@
       target: the CoverageTarget to use as basis for coverage calculation
       device_coverage_path: location of coverage file on device
       output_path: path to place output files in. If None will use
-        <android_root_path>/<_COVERAGE_REPORT_PATH>/<target>/<test[-qualifier]>
+        <android_out_path>/<_COVERAGE_REPORT_PATH>/<target>/<test[-qualifier]>
       test_qualifier: designates mode test was run with. e.g size=small.
         If not None, this will be used to customize output_path as shown above.
 
@@ -89,7 +90,7 @@
       report_name = test_suite_name
       if test_qualifier:
         report_name = report_name + "-" + test_qualifier
-      output_path = os.path.join(self._root_path,
+      output_path = os.path.join(self._out_path,
                                  self._COVERAGE_REPORT_PATH,
                                  target.GetName(),
                                  report_name)
@@ -153,7 +154,7 @@
 
   def _GetBuildIntermediatePath(self, target):
     return os.path.join(
-        self._root_path, self._TARGET_INTERMEDIATES_BASE_PATH, target.GetType(),
+        self._out_path, self._TARGET_INTERMEDIATES_BASE_PATH, target.GetType(),
         "%s_intermediates" % target.GetName())
 
   def _GatherSrcs(self, targets):
diff --git a/testrunner/runtest.py b/testrunner/runtest.py
index ba09d97..470dc42 100755
--- a/testrunner/runtest.py
+++ b/testrunner/runtest.py
@@ -78,13 +78,15 @@
   # regular expression to match install: statements in make output
   _RE_MAKE_INSTALL = re.compile(r'Install:\s(.+)')
 
-  # regular expression to find remote device path from a file path relative
-  # to build root
-  _RE_MAKE_INSTALL_PATH = re.compile(r'out\/target\/product\/\w+\/(.+)$')
 
   def __init__(self):
     # disable logging of timestamp
     self._root_path = android_build.GetTop()
+    out_base_name = os.path.basename(android_build.GetOutDir())
+    # regular expression to find remote device path from a file path relative
+    # to build root
+    pattern = r'' + out_base_name + r'\/target\/product\/\w+\/(.+)$'
+    self._re_make_install_path = re.compile(pattern)
     logger.SetTimestampLogging(False)
     self._adb = None
     self._known_tests = None
@@ -298,7 +300,7 @@
           self._PushInstallFileToDevice(install_path)
 
   def _PushInstallFileToDevice(self, install_path):
-    m = self._RE_MAKE_INSTALL_PATH.match(install_path)
+    m = self._re_make_install_path.match(install_path)
     if m:
       remote_path = m.group(1)
       remote_dir = os.path.dirname(remote_path)
diff --git a/testrunner/test_defs/native_test.py b/testrunner/test_defs/native_test.py
index dc26c73..caef877 100644
--- a/testrunner/test_defs/native_test.py
+++ b/testrunner/test_defs/native_test.py
@@ -154,7 +154,7 @@
 
     Args:
       binary: basename of the file to be run. It is expected to be under
-            out/host/<os>-<arch>/bin.
+            $ANDROID_HOST_OUT/bin.
       valgrind: If True the command will be run under valgrind.
 
     Returns: