am 9d0a4a6e: am 5f3ed7dd: am 80bc4f93: Merge "Refresh 64-bit headers/libs (WW20)"

* commit '9d0a4a6eca86933e9cd1fd60ba8cc0abae351b2a':
  Refresh 64-bit headers/libs (WW20)
diff --git a/apps/Development/res/layout/connectivity.xml b/apps/Development/res/layout/connectivity.xml
index 53f1ed7..2aaf6c6 100644
--- a/apps/Development/res/layout/connectivity.xml
+++ b/apps/Development/res/layout/connectivity.xml
@@ -219,6 +219,15 @@
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@string/start_tdls" />
+        <Button android:id="@+id/stopTdls"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:text="@string/stop_tdls" />
+    </LinearLayout>
+    <LinearLayout
+      android:orientation="horizontal"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content">
         <TextView
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
@@ -227,10 +236,6 @@
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:minEms="10" />
-        <Button android:id="@+id/stopTdls"
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:text="@string/stop_tdls" />
     </LinearLayout>
 
     <!-- divider line -->
@@ -279,6 +284,14 @@
       android:orientation="horizontal"
       android:layout_width="match_parent"
       android:layout_height="wrap_content">
+        <TextView
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:text="@string/netid" />
+        <EditText android:id="@+id/netid"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:minEms="5" />
         <Button android:id="@+id/add_default_route"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
diff --git a/apps/Development/res/values/strings.xml b/apps/Development/res/values/strings.xml
index ced7b72..0c13987 100644
--- a/apps/Development/res/values/strings.xml
+++ b/apps/Development/res/values/strings.xml
@@ -43,6 +43,7 @@
     <string name="start_hipri">Start HiPri</string>
     <string name="stop_hipri">Stop HiPri</string>
     <string name="crash">CRASH</string>
+    <string name="netid">NetId</string>
     <string name="add_default_route">Add Default Route</string>
     <string name="remove_default_route">Remove Default Route</string>
     <string name="default_request">Make a http request</string>
diff --git a/apps/Development/src/com/android/development/Connectivity.java b/apps/Development/src/com/android/development/Connectivity.java
index 7d4491b..55e5350 100644
--- a/apps/Development/src/com/android/development/Connectivity.java
+++ b/apps/Development/src/com/android/development/Connectivity.java
@@ -524,7 +524,8 @@
 
     private void onAddDefaultRoute() {
         try {
-            mNetd.addRoute("eth0", new RouteInfo(null,
+            int netId = Integer.valueOf(((TextView) findViewById(R.id.netid)).getText().toString());
+            mNetd.addRoute(netId, new RouteInfo(null,
                     NetworkUtils.numericToInetAddress("8.8.8.8")));
         } catch (Exception e) {
             Log.e(TAG, "onAddDefaultRoute got exception: " + e.toString());
@@ -533,7 +534,8 @@
 
     private void onRemoveDefaultRoute() {
         try {
-            mNetd.removeRoute("eth0", new RouteInfo(null,
+            int netId = Integer.valueOf(((TextView) findViewById(R.id.netid)).getText().toString());
+            mNetd.removeRoute(netId, new RouteInfo(null,
                     NetworkUtils.numericToInetAddress("8.8.8.8")));
         } catch (Exception e) {
             Log.e(TAG, "onRemoveDefaultRoute got exception: " + e.toString());
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-az-rAZ/strings.xml
similarity index 70%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-az-rAZ/strings.xml
index d59ae53..8e1956a 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-az-rAZ/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
-    <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
-    <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+    <string name="appTitle" msgid="161410001913116606">"Son çarə"</string>
+    <string name="title" msgid="8156274565006125136">"Dəstəklənməyən fəaliyyət"</string>
+    <string name="error" msgid="6539615832923362301">"Bu fəaliyyət hazırda dəstəklənmir."</string>
 </resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-az/strings.xml
similarity index 70%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-az/strings.xml
index d59ae53..8e1956a 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-az/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
-    <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
-    <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+    <string name="appTitle" msgid="161410001913116606">"Son çarə"</string>
+    <string name="title" msgid="8156274565006125136">"Dəstəklənməyən fəaliyyət"</string>
+    <string name="error" msgid="6539615832923362301">"Bu fəaliyyət hazırda dəstəklənmir."</string>
 </resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-en-rIN/strings.xml
similarity index 70%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-en-rIN/strings.xml
index d59ae53..a7c82cb 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-en-rIN/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
-    <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
-    <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+    <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+    <string name="title" msgid="8156274565006125136">"Unsupported action"</string>
+    <string name="error" msgid="6539615832923362301">"That action is not currently supported."</string>
 </resources>
diff --git a/apps/Fallback/res/values-et/strings.xml b/apps/Fallback/res/values-et-rEE/strings.xml
similarity index 100%
rename from apps/Fallback/res/values-et/strings.xml
rename to apps/Fallback/res/values-et-rEE/strings.xml
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-fr-rCA/strings.xml
similarity index 70%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-fr-rCA/strings.xml
index d59ae53..a751b97 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-fr-rCA/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
-    <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
-    <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+    <string name="appTitle" msgid="161410001913116606">"Application de secours"</string>
+    <string name="title" msgid="8156274565006125136">"Action non prise en charge"</string>
+    <string name="error" msgid="6539615832923362301">"Cette action n\'est actuellement pas prise en charge."</string>
 </resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-hy-rAM/strings.xml
similarity index 70%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-hy-rAM/strings.xml
index d59ae53..1547741 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-hy-rAM/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
-    <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
-    <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+    <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+    <string name="title" msgid="8156274565006125136">"Չաջակցվող գործողություն"</string>
+    <string name="error" msgid="6539615832923362301">"Այդ գործողությունն այժմ չի աջակցվում:"</string>
 </resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-ka-rGE/strings.xml
similarity index 65%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-ka-rGE/strings.xml
index d59ae53..469a135 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-ka-rGE/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
-    <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
-    <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+    <string name="appTitle" msgid="161410001913116606">"შემოვლით რეჟიმში გადასვლა"</string>
+    <string name="title" msgid="8156274565006125136">"მოქმედება მხარდაჭერილი არ არის"</string>
+    <string name="error" msgid="6539615832923362301">"ეს მოქმედება ამჟამად მხარდაუჭერელია."</string>
 </resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-km-rKH/strings.xml
similarity index 66%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-km-rKH/strings.xml
index d59ae53..a442335 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-km-rKH/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
-    <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
-    <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+    <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+    <string name="title" msgid="8156274565006125136">"សកម្មភាព​មិន​បាន​គាំទ្រ"</string>
+    <string name="error" msgid="6539615832923362301">"បច្ចុប្បន្ន​សកម្មភាព​នោះ​មិន​ត្រូវ​បាន​គាំទ្រ​ទេ។"</string>
 </resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-lo-rLA/strings.xml
similarity index 69%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-lo-rLA/strings.xml
index d59ae53..948b60f 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-lo-rLA/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
-    <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
-    <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+    <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+    <string name="title" msgid="8156274565006125136">"ການເຮັດວຽກທີ່ບໍ່ຮອງຮັບ"</string>
+    <string name="error" msgid="6539615832923362301">"ການເຮັດວຽກນັ້ນຍັງບໍ່ຮອງຮັບເທື່ອ"</string>
 </resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-mn-rMN/strings.xml
similarity index 70%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-mn-rMN/strings.xml
index d59ae53..8cb3870 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-mn-rMN/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
-    <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
-    <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+    <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+    <string name="title" msgid="8156274565006125136">"Дэмжигдээгүй үйлдэл"</string>
+    <string name="error" msgid="6539615832923362301">"Энэ үйлдэл одоогоор дэмжигдээгүй."</string>
 </resources>
diff --git a/apps/Fallback/res/values-ms/strings.xml b/apps/Fallback/res/values-ms-rMY/strings.xml
similarity index 100%
rename from apps/Fallback/res/values-ms/strings.xml
rename to apps/Fallback/res/values-ms-rMY/strings.xml
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-ne-rNP/strings.xml
similarity index 71%
rename from apps/Fallback/res/values-be/strings.xml
rename to apps/Fallback/res/values-ne-rNP/strings.xml
index d59ae53..7d27eff 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-ne-rNP/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
-    <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
-    <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+    <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+    <string name="title" msgid="8156274565006125136">"असमर्थित कार्य"</string>
+    <string name="error" msgid="6539615832923362301">"यस कारवाही हाल समर्थित छैन।"</string>
 </resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-ne/strings.xml
similarity index 71%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-ne/strings.xml
index d59ae53..7d27eff 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-ne/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
-    <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
-    <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+    <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+    <string name="title" msgid="8156274565006125136">"असमर्थित कार्य"</string>
+    <string name="error" msgid="6539615832923362301">"यस कारवाही हाल समर्थित छैन।"</string>
 </resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-si-rLK/strings.xml
similarity index 69%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-si-rLK/strings.xml
index d59ae53..8a7e7a5 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-si-rLK/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
-    <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
-    <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+    <string name="appTitle" msgid="161410001913116606">"පසු බැසීම"</string>
+    <string name="title" msgid="8156274565006125136">"සහය නොදක්වන ක්‍රියාව"</string>
+    <string name="error" msgid="6539615832923362301">"එම ක්‍රියාවට දැන් සහය නොදක්වයි."</string>
 </resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-si/strings.xml
similarity index 69%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-si/strings.xml
index d59ae53..8a7e7a5 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-si/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
-    <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
-    <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+    <string name="appTitle" msgid="161410001913116606">"පසු බැසීම"</string>
+    <string name="title" msgid="8156274565006125136">"සහය නොදක්වන ක්‍රියාව"</string>
+    <string name="error" msgid="6539615832923362301">"එම ක්‍රියාවට දැන් සහය නොදක්වයි."</string>
 </resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-zh-rHK/strings.xml
similarity index 70%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-zh-rHK/strings.xml
index d59ae53..ce01c92 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-zh-rHK/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
-    <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
-    <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+    <string name="appTitle" msgid="161410001913116606">"後備"</string>
+    <string name="title" msgid="8156274565006125136">"不支援的操作"</string>
+    <string name="error" msgid="6539615832923362301">"目前不支援該操作。"</string>
 </resources>
diff --git a/build/Android.mk b/build/Android.mk
index a3f1464..8bfa64f 100644
--- a/build/Android.mk
+++ b/build/Android.mk
@@ -126,6 +126,8 @@
     android-support-v7-mediarouter \
     android-support-v7-recyclerview \
     android-support-v13 \
-    android-support-v17-leanback
+    android-support-v17-leanback \
+    android-support-multidex \
+    android-support-multidex-instrumentation
 
 $(foreach lib, $(ANDROID_SUPPORT_LIBRARIES), $(eval $(call _package_sdk_library,$(lib))))
diff --git a/build/sdk.atree b/build/sdk.atree
index 88b448a..5a10440 100644
--- a/build/sdk.atree
+++ b/build/sdk.atree
@@ -369,6 +369,25 @@
 ${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
 ${OUT_DIR}/target/common/obj/PACKAGING/android-support-v4_intermediates/android-support-v4.jar                        extras/android/support/v7/appcompat/libs/android-support-v4.jar
 
+frameworks/multidex/library/README.txt                                                            extras/android/support/multidex/library/README.txt
+frameworks/multidex/library/.project                                                              extras/android/support/multidex/library/.project
+frameworks/multidex/library/.classpath                                                            extras/android/support/multidex/library/.classpath
+frameworks/multidex/library/AndroidManifest.xml                                                   extras/android/support/multidex/library/AndroidManifest.xml
+frameworks/multidex/library/project.properties                                                    extras/android/support/multidex/library/project.properties
+frameworks/multidex/library/src/.readme                                                           extras/android/support/multidex/library/src/.readme
+frameworks/multidex/library/res/.readme                                                           extras/android/support/multidex/library/res/.readme
+${OUT_DIR}/target/common/obj/PACKAGING/android-support-multidex_intermediates/android-support-multidex.jar              extras/android/support/multidex/library/libs/android-support-multidex.jar
+
+frameworks/multidex/instrumentation/README.txt                                                         extras/android/support/multidex/instrumentation/README.txt
+frameworks/multidex/instrumentation/.project                                                           extras/android/support/multidex/instrumentation/.project
+frameworks/multidex/instrumentation/.classpath                                                         extras/android/support/multidex/instrumentation/.classpath
+frameworks/multidex/instrumentation/AndroidManifest.xml                                                extras/android/support/multidex/instrumentation/AndroidManifest.xml
+frameworks/multidex/instrumentation/project.properties                                                 extras/android/support/multidex/instrumentation/project.properties
+frameworks/multidex/instrumentation/src/.readme                                                        extras/android/support/multidex/instrumentation/src/.readme
+frameworks/multidex/instrumentation/res/.readme                                                        extras/android/support/multidex/instrumentation/res/.readme
+${OUT_DIR}/target/common/obj/PACKAGING/android-support-multidex-instrumentation_intermediates/android-support-multidex-instrumentation.jar      extras/android/support/multidex/instrumentation/libs/android-support-multidex-instrumentation.jar
+${OUT_DIR}/target/common/obj/PACKAGING/android-support-multidex_intermediates/android-support-multidex.jar                                      extras/android/support/multidex/instrumentation/libs/android-support-multidex.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
@@ -398,6 +417,5 @@
 # Tests Component
 ##############################################################################
 framework/layoutlib-tests.jar tests/libtests/layoutlib-tests.jar
-system/app/ConnectivityTest.apk tests/emulator-test-apps/ConnectivityTest.apk
-system/app/GpsLocationTest.apk tests/emulator-test-apps/GpsLocationTest.apk
+system/app/EmulatorSmokeTests.apk tests/emulator-test-apps/EmulatorSmokeTests.apk
 
diff --git a/build/windows_sdk_whitelist.mk b/build/windows_sdk_whitelist.mk
index e175fad..7f22c8c 100644
--- a/build/windows_sdk_whitelist.mk
+++ b/build/windows_sdk_whitelist.mk
@@ -51,6 +51,7 @@
 	frameworks/compile \
 	frameworks/native \
 	frameworks/rs \
+	frameworks/tools \
 	system/core/adb \
 	system/core/fastboot \
 	system/core/libcutils \
diff --git a/cmds/monkey/src/com/android/commands/monkey/Monkey.java b/cmds/monkey/src/com/android/commands/monkey/Monkey.java
index a2655e1..dfcb4b0 100644
--- a/cmds/monkey/src/com/android/commands/monkey/Monkey.java
+++ b/cmds/monkey/src/com/android/commands/monkey/Monkey.java
@@ -1150,6 +1150,7 @@
             if (ev != null) {
                 int injectCode = ev.injectEvent(mWm, mAm, mVerbose);
                 if (injectCode == MonkeyEvent.INJECT_FAIL) {
+                    System.out.println("    // Injection Failed");
                     if (ev instanceof MonkeyKeyEvent) {
                         mDroppedKeyEvents++;
                     } else if (ev instanceof MonkeyMotionEvent) {
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
index a7f538d..af6a231 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
@@ -436,6 +436,7 @@
 
             if (lastKey != KeyEvent.KEYCODE_POWER
                     && lastKey != KeyEvent.KEYCODE_ENDCALL
+                    && lastKey != KeyEvent.KEYCODE_SLEEP
                     && PHYSICAL_KEY_EXISTS[lastKey]) {
                 break;
             }
diff --git a/ide/eclipse/.classpath b/ide/eclipse/.classpath
index af99325..5bd032f 100644
--- a/ide/eclipse/.classpath
+++ b/ide/eclipse/.classpath
@@ -22,7 +22,6 @@
 	<classpathentry kind="src" path="packages/apps/Nfc/src"/>
 	<classpathentry kind="src" path="packages/apps/Nfc/nci/src"/>
 	<classpathentry kind="src" path="packages/apps/PackageInstaller/src"/>
-	<classpathentry kind="src" path="packages/apps/Phone/src"/>
 	<classpathentry kind="src" path="packages/apps/PhoneCommon/src"/>
 	<classpathentry kind="src" path="packages/apps/QuickSearchBox/src"/>
 	<classpathentry kind="src" path="packages/apps/Provision/src"/>
@@ -39,8 +38,11 @@
 	<classpathentry kind="src" path="packages/screensavers/Basic/src"/>
 	<classpathentry kind="src" path="packages/screensavers/PhotoTable/src"/>
 	<classpathentry kind="src" path="packages/screensavers/WebView/src"/>
+	<classpathentry kind="src" path="packages/services/Telecomm/src"/>
+	<classpathentry kind="src" path="packages/services/Telecomm/tests/src"/>
 	<classpathentry kind="src" path="packages/services/Telephony/src"/>
 	<classpathentry kind="src" path="packages/services/Telephony/common/src"/>
+	<classpathentry kind="src" path="packages/services/Telephony/tests/src"/>
 	<classpathentry kind="src" path="frameworks/base/cmds/am/src"/>
 	<classpathentry kind="src" path="frameworks/base/cmds/input/src"/>
 	<classpathentry kind="src" path="frameworks/base/cmds/pm/src"/>
@@ -64,13 +66,15 @@
 	<classpathentry kind="src" path="frameworks/base/packages/SettingsProvider/src"/>
 	<classpathentry kind="src" path="frameworks/base/packages/SystemUI/src"/>
 	<classpathentry kind="src" path="frameworks/base/policy/src"/>
+	<classpathentry kind="src" path="frameworks/base/rs/java"/>
 	<classpathentry kind="src" path="frameworks/base/sax/java"/>
 	<classpathentry kind="src" path="frameworks/base/services/core/java"/>
-        <classpathentry kind="src" path="frameworks/base/services/accessibility/java"/>
-        <classpathentry kind="src" path="frameworks/base/services/print/java"/>
-        <classpathentry kind="src" path="frameworks/base/services/backup/java"/>
-        <classpathentry kind="src" path="frameworks/base/services/devicepolicy/java"/>
-        <classpathentry kind="src" path="frameworks/base/services/appwidget/java"/>
+	<classpathentry kind="src" path="frameworks/base/services/accessibility/java"/>
+	<classpathentry kind="src" path="frameworks/base/services/print/java"/>
+	<classpathentry kind="src" path="frameworks/base/services/backup/java"/>
+	<classpathentry kind="src" path="frameworks/base/services/devicepolicy/java"/>
+	<classpathentry kind="src" path="frameworks/base/services/appwidget/java"/>
+	<classpathentry kind="src" path="frameworks/base/telecomm/java"/>
 	<classpathentry kind="src" path="frameworks/base/telephony/java"/>
 	<classpathentry kind="src" path="frameworks/base/test-runner/src"/>
 	<classpathentry kind="src" path="frameworks/base/wifi/java"/>
@@ -84,6 +88,7 @@
 	<classpathentry kind="src" path="frameworks/opt/telephony/src/java"/>
 	<classpathentry kind="src" path="frameworks/opt/mms/src/java"/>
 	<classpathentry kind="src" path="frameworks/opt/net/voip/src/java"/>
+	<classpathentry kind="src" path="frameworks/opt/net/wifi/service/java"/>
 	<classpathentry kind="src" path="frameworks/opt/vcard/java"/>
 	<classpathentry kind="src" path="frameworks/support/renderscript/v8/java/src"/>
 	<classpathentry kind="src" path="frameworks/support/v13/java"/>
@@ -116,7 +121,6 @@
 	<classpathentry kind="src" path="out/target/common/obj/APPS/Gallery2_intermediates/src/renderscript/src"/>
 	<classpathentry kind="src" path="out/target/common/obj/APPS/MediaProvider_intermediates/src/src"/>
 	<classpathentry kind="src" path="out/target/common/obj/APPS/Music_intermediates/src/src"/>
-	<classpathentry kind="src" path="out/target/common/obj/APPS/Phone_intermediates/src/src"/>
 	<classpathentry kind="src" path="out/target/common/obj/APPS/QuickSearchBox_intermediates/src/src"/>
 	<classpathentry kind="src" path="out/target/common/obj/APPS/SystemUI_intermediates/src/src"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/android-common-carousel_intermediates/src/renderscript/src"/>
@@ -125,6 +129,7 @@
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/keystore/java"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/location/java"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/media/java"/>
+	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/telecomm/java"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/telephony/java"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/wifi/java"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/NfcLogTags_intermediates/src/src"/>
diff --git a/ide/eclipse/android-formatting.xml b/ide/eclipse/android-formatting.xml
index 9b43767..9c2af85 100644
--- a/ide/eclipse/android-formatting.xml
+++ b/ide/eclipse/android-formatting.xml
@@ -52,7 +52,7 @@
 <setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
 <setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
 <setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
-<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="100"/>
 <setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
 <setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
 <setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
diff --git a/samples/ApiDemos/AndroidManifest.xml b/samples/ApiDemos/AndroidManifest.xml
index f202d59..55a04f0 100644
--- a/samples/ApiDemos/AndroidManifest.xml
+++ b/samples/ApiDemos/AndroidManifest.xml
@@ -37,7 +37,7 @@
     <!-- For android.media.audiofx.Visualizer -->
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
 
-    <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="17" />
+    <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="20" />
 
     <!-- We will request access to the camera, saying we require a camera
          of some sort but not one with autofocus capability. -->
@@ -78,7 +78,7 @@
 
         <activity android:name=".app.DialogActivity"
                 android:label="@string/activity_dialog"
-                android:theme="@android:style/Theme.Holo.Dialog">
+                android:theme="@style/ThemeCurrentDialog">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.SAMPLE_CODE" />
@@ -740,7 +740,7 @@
 <!-- BEGIN_INCLUDE(interstitial_affinity) -->
         <activity android:name=".app.IncomingMessageInterstitial"
                 android:label="You have messages"
-                android:theme="@style/ThemeHoloDialog"
+                android:theme="@style/ThemeCurrentDialog"
                 android:launchMode="singleTask"
                 android:taskAffinity=""
                 android:excludeFromRecents="true">
@@ -1232,6 +1232,15 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".content.DocumentsSample"
+                android:label="@string/activity_documents"
+                android:enabled="@bool/atLeastKitKat">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
         <provider android:name=".content.FileProvider"
                   android:authorities="com.example.android.apis.content.FileProvider"
                   android:enabled="@bool/atLeastHoneycombMR2" />
@@ -1258,13 +1267,6 @@
             </intent-filter>
         </activity>
 
-        <activity android:name=".os.Sensors" android:label="OS/Sensors">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.SAMPLE_CODE" />
-            </intent-filter>
-        </activity>
-
         <activity android:name=".os.TriggerSensors" android:label="OS/TriggerSensors">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -1300,6 +1302,25 @@
         <!--     ANDROID.ANIMATION PACKAGE SAMPLES         -->
         <!-- ************************************* -->
 
+        <activity android:name=".animation.ActivityTransition"
+                android:label="Animation/Activity Transition"
+                android:enabled="@bool/atLeastLRelease"
+                android:theme="@style/ActivityTransitionTheme">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".animation.ActivityTransitionDetails"
+                android:label="Animation/Details of a specific thingy"
+                android:enabled="@bool/atLeastLRelease"
+                android:theme="@style/ActivityTransitionTheme">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".animation.AnimationLoading"
                 android:label="Animation/Loading"
                 android:enabled="@bool/atLeastHoneycomb">
@@ -1417,6 +1438,15 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".animation.PathAnimations"
+                  android:label="Animation/Path Animations"
+                  android:enabled="@bool/atLeastHoneycomb">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
         <!-- ************************************* -->
         <!--     ANIMATION PACKAGE SAMPLES         -->
         <!-- ************************************* -->
@@ -1976,20 +2006,6 @@
             </intent-filter>
         </activity>
 
-        <activity android:name=".view.Gallery1" android:label="Views/Gallery/1. Photos">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.SAMPLE_CODE" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".view.Gallery2" android:label="Views/Gallery/2. People">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.SAMPLE_CODE" />
-            </intent-filter>
-        </activity>
-
         <activity android:name=".view.Spinner1" android:label="Views/Spinner">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -2027,14 +2043,6 @@
             </intent-filter>
         </activity>
 
-        <activity android:name=".view.ImageSwitcher1"
-                android:label="Views/ImageSwitcher">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.SAMPLE_CODE" />
-            </intent-filter>
-        </activity>
-
         <activity android:name=".view.TextSwitcher1"
                 android:label="Views/TextSwitcher">
             <intent-filter>
@@ -2160,8 +2168,9 @@
         </activity>
 
         <activity android:name=".view.Controls5"
-                  android:label="Views/Controls/5. Custom Theme"
-                  android:theme="@style/CustomTheme">
+                  android:label="Views/Controls/5. Quantum Light Theme"
+                  android:theme="@android:style/Theme.Quantum.Light"
+                  android:enabled="@bool/atLeastLRelease">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.SAMPLE_CODE" />
@@ -2169,8 +2178,36 @@
         </activity>
 
         <activity android:name=".view.Controls6"
-                  android:label="Views/Controls/6. Holo or Old Theme"
-                  android:theme="@style/ThemeHolo">
+                  android:label="Views/Controls/6. Quantum Dark Theme"
+                  android:theme="@android:style/Theme.Quantum"
+                  android:enabled="@bool/atLeastLRelease">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".view.Controls7"
+                  android:label="Views/Controls/7. Custom Theme"
+                  android:theme="@style/CustomTheme">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".view.Controls8"
+                  android:label="Views/Controls/8. Current or Old Theme"
+                  android:theme="@style/ThemeCurrent">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".view.Controls9"
+                  android:label="Views/Controls/9. Default Theme"
+                  android:theme="@style/ThemeDefault">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.SAMPLE_CODE" />
@@ -2584,7 +2621,7 @@
 
         <activity android:name=".graphics.TriangleActivity"
                 android:label="Graphics/OpenGL ES/Textured Triangle"
-                android:theme="@android:style/Theme.Holo.Dialog"
+                android:theme="@style/ThemeCurrentDialog"
                 android:configChanges="keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/samples/ApiDemos/res/drawable-nodpi/ball.jpg b/samples/ApiDemos/res/drawable-nodpi/ball.jpg
new file mode 100644
index 0000000..2960b73
--- /dev/null
+++ b/samples/ApiDemos/res/drawable-nodpi/ball.jpg
Binary files differ
diff --git a/samples/ApiDemos/res/drawable-nodpi/block.jpg b/samples/ApiDemos/res/drawable-nodpi/block.jpg
new file mode 100644
index 0000000..04c22a0
--- /dev/null
+++ b/samples/ApiDemos/res/drawable-nodpi/block.jpg
Binary files differ
diff --git a/samples/ApiDemos/res/drawable-nodpi/ducky.jpg b/samples/ApiDemos/res/drawable-nodpi/ducky.jpg
new file mode 100644
index 0000000..830bbe3
--- /dev/null
+++ b/samples/ApiDemos/res/drawable-nodpi/ducky.jpg
Binary files differ
diff --git a/samples/ApiDemos/res/drawable-nodpi/jellies.jpg b/samples/ApiDemos/res/drawable-nodpi/jellies.jpg
new file mode 100644
index 0000000..ee2b5c6
--- /dev/null
+++ b/samples/ApiDemos/res/drawable-nodpi/jellies.jpg
Binary files differ
diff --git a/samples/ApiDemos/res/drawable-nodpi/mug.jpg b/samples/ApiDemos/res/drawable-nodpi/mug.jpg
new file mode 100644
index 0000000..e149e19
--- /dev/null
+++ b/samples/ApiDemos/res/drawable-nodpi/mug.jpg
Binary files differ
diff --git a/samples/ApiDemos/res/drawable-nodpi/pencil.jpg b/samples/ApiDemos/res/drawable-nodpi/pencil.jpg
new file mode 100644
index 0000000..e348311
--- /dev/null
+++ b/samples/ApiDemos/res/drawable-nodpi/pencil.jpg
Binary files differ
diff --git a/samples/ApiDemos/res/drawable-nodpi/scissors.jpg b/samples/ApiDemos/res/drawable-nodpi/scissors.jpg
new file mode 100644
index 0000000..caf0ce8
--- /dev/null
+++ b/samples/ApiDemos/res/drawable-nodpi/scissors.jpg
Binary files differ
diff --git a/samples/ApiDemos/res/drawable-nodpi/woot.jpg b/samples/ApiDemos/res/drawable-nodpi/woot.jpg
new file mode 100644
index 0000000..ccaef67
--- /dev/null
+++ b/samples/ApiDemos/res/drawable-nodpi/woot.jpg
Binary files differ
diff --git a/samples/ApiDemos/res/layout/controls_1.xml b/samples/ApiDemos/res/layout/controls_1.xml
index e280188..cd7fd0d 100644
--- a/samples/ApiDemos/res/layout/controls_1.xml
+++ b/samples/ApiDemos/res/layout/controls_1.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
+<!--
+     Copyright (C) 2007 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.
@@ -15,139 +16,143 @@
 -->
 
 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:orientation="vertical" >
 
     <LinearLayout
-        android:orientation="vertical"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content">
+        android:layout_height="wrap_content"
+        android:orientation="vertical" >
 
-       <LinearLayout
-           android:orientation="horizontal"
-           android:layout_width="match_parent"
-           android:layout_height="wrap_content">
-
-        <Button android:id="@+id/button"
-            android:text="@string/controls_1_save"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"/>
-
-        <Button android:id="@+id/button_disabled"
-            android:text="@string/controls_1_save"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"/>
-
-      </LinearLayout>
-
-      <LinearLayout
-        android:orientation="horizontal"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content">
-
-        <EditText android:id="@+id/edit"
+        <LinearLayout
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"/>
+            android:layout_height="wrap_content"
+            android:orientation="horizontal" >
 
-        <EditText android:id="@+id/edit2"
+            <Button
+                android:id="@+id/button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/controls_1_save" />
+
+            <Button
+                android:id="@+id/button_disabled"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/controls_1_save" />
+        </LinearLayout>
+
+        <LinearLayout
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"/>
+            android:layout_height="wrap_content"
+            android:orientation="horizontal" >
 
-      </LinearLayout>
+            <EditText
+                android:id="@+id/edit"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1" />
 
-        <CheckBox android:id="@+id/check1"
-            android:paddingBottom="24sp"
-	        android:paddingTop="24sp"
+            <EditText
+                android:id="@+id/edit2"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1" />
+        </LinearLayout>
+
+        <CheckBox
+            android:id="@+id/check1"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:paddingBottom="24sp"
+            android:paddingTop="24sp"
             android:text="@string/controls_1_checkbox_1" />
 
-        <CheckBox android:id="@+id/check2"
+        <CheckBox
+            android:id="@+id/check2"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/controls_1_checkbox_2" />
-    
+
         <RadioGroup
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:orientation="vertical">
-    
-            <RadioButton android:id="@+id/radio1"
+            android:orientation="vertical" >
+
+            <RadioButton
+                android:id="@+id/radio1"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:text="@string/controls_1_radiobutton_1" />
-    
-            <RadioButton android:id="@+id/radio2"
+
+            <RadioButton
+                android:id="@+id/radio2"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:text="@string/controls_1_radiobutton_2" />
-    
         </RadioGroup>
-    
-        <CheckBox android:id="@+id/star"
+
+        <CheckBox
+            android:id="@+id/star"
             style="?android:attr/starStyle"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/controls_1_star" />
-                            
-        <ToggleButton android:id="@+id/toggle1"
+
+        <ToggleButton
+            android:id="@+id/toggle1"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content" />
-   
-        <ToggleButton android:id="@+id/toggle2"
+
+        <ToggleButton
+            android:id="@+id/toggle2"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content" />
-             
-        <Spinner android:id="@+id/spinner1"
+
+        <Spinner
+            android:id="@+id/spinner1"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:drawSelectorOnTop="true"
-        />
+            android:drawSelectorOnTop="true" />
 
         <TextView
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginTop="5dip"
-            android:text="@string/textColorPrimary"
-            android:textAppearance="?android:attr/textAppearanceLarge"
             android:focusable="true"
-        />
+            android:text="@string/textColorPrimary"
+            android:textAppearance="?android:attr/textAppearanceLarge" />
 
         <TextView
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginTop="5dip"
+            android:focusable="true"
             android:text="@string/textColorSecondary"
             android:textAppearance="?android:attr/textAppearanceLarge"
-            android:textColor="?android:attr/textColorSecondary"
-            android:focusable="true"
-        />
+            android:textColor="?android:attr/textColorSecondary" />
 
         <TextView
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginTop="5dip"
+            android:focusable="true"
             android:text="@string/textColorTertiary"
             android:textAppearance="?android:attr/textAppearanceLarge"
-            android:textColor="?android:attr/textColorTertiary"
-            android:focusable="true"
-        />
+            android:textColor="?android:attr/textColorTertiary" />
 
         <TextView
             style="?android:attr/listSeparatorTextViewStyle"
-            android:text="@string/listSeparatorTextViewStyle"
             android:layout_marginTop="5dip"
-        />
+            android:text="@string/listSeparatorTextViewStyle" />
 
         <TextView
-            android:layout_height="wrap_content"
             android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
             android:layout_marginTop="400dip"
-            android:textAppearance="?android:attr/textAppearanceLarge"
             android:text="(And all inside of a ScrollView!)"
-        />
-        
+            android:textAppearance="?android:attr/textAppearanceLarge" />
     </LinearLayout>
 
-</ScrollView>
+</ScrollView>
\ No newline at end of file
diff --git a/samples/ApiDemos/res/layout/gallery_1.xml b/samples/ApiDemos/res/layout/gallery_1.xml
deleted file mode 100644
index d884c61..0000000
--- a/samples/ApiDemos/res/layout/gallery_1.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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:id="@+id/layout2"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-<Gallery  android:id="@+id/gallery"
-android:layout_width="match_parent"
-android:layout_height="wrap_content"
-/>
-<EditText
- android:text="@+id/EditText01"
- android:id="@+id/EditText01"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"></EditText>
-</LinearLayout>
\ No newline at end of file
diff --git a/samples/ApiDemos/res/layout/gallery_2.xml b/samples/ApiDemos/res/layout/gallery_2.xml
deleted file mode 100644
index 1192bb2..0000000
--- a/samples/ApiDemos/res/layout/gallery_2.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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="wrap_content">
-
-    <Button
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
-        android:layout_marginBottom="10dip"
-        android:text="@string/gallery_2_text"
-    />
-
-    <Gallery android:id="@+id/gallery"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center_vertical"
-        android:spacing="16dp"
-    />
-
-</LinearLayout>
-
diff --git a/samples/ApiDemos/res/layout/image_block.xml b/samples/ApiDemos/res/layout/image_block.xml
new file mode 100644
index 0000000..4233717
--- /dev/null
+++ b/samples/ApiDemos/res/layout/image_block.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:clipChildren="true"
+            android:columnCount="2"
+            android:rowCount="4"
+        >
+    <ImageView android:id="@+id/ducky"
+               android:layout_height="wrap_content"
+               android:layout_width="wrap_content"
+               android:scaleType="centerCrop"
+               android:layout_column="0"
+               android:layout_row="0"
+               android:src="@drawable/ducky"
+               android:onClick="clicked"
+               android:viewName="ducky"
+            />
+    <ImageView android:id="@+id/woot"
+               android:layout_height="wrap_content"
+               android:layout_width="wrap_content"
+               android:scaleType="centerCrop"
+               android:src="@drawable/woot"
+               android:layout_column="1"
+               android:layout_row="0"
+               android:onClick="clicked"
+               android:viewName="woot"
+            />
+    <ImageView android:id="@+id/ball"
+               android:layout_height="wrap_content"
+               android:layout_width="wrap_content"
+               android:scaleType="centerCrop"
+               android:src="@drawable/ball"
+               android:layout_column="0"
+               android:layout_row="1"
+               android:onClick="clicked"
+               android:viewName="ball"
+            />
+    <ImageView android:id="@+id/block"
+               android:layout_height="wrap_content"
+               android:layout_width="wrap_content"
+               android:scaleType="centerCrop"
+               android:src="@drawable/block"
+               android:layout_column="1"
+               android:layout_row="1"
+               android:onClick="clicked"
+               android:viewName="block"
+            />
+    <ImageView android:id="@+id/jellies"
+               android:layout_height="wrap_content"
+               android:layout_width="wrap_content"
+               android:scaleType="centerCrop"
+               android:src="@drawable/jellies"
+               android:layout_column="0"
+               android:layout_row="2"
+               android:onClick="clicked"
+               android:viewName="jellies"
+            />
+    <ImageView android:id="@+id/mug"
+               android:layout_height="wrap_content"
+               android:layout_width="wrap_content"
+               android:scaleType="centerCrop"
+               android:src="@drawable/mug"
+               android:layout_column="1"
+               android:layout_row="2"
+               android:onClick="clicked"
+               android:viewName="mug"
+            />
+    <ImageView android:id="@+id/pencil"
+               android:layout_height="wrap_content"
+               android:layout_width="wrap_content"
+               android:scaleType="centerCrop"
+               android:src="@drawable/pencil"
+               android:layout_column="0"
+               android:layout_row="3"
+               android:onClick="clicked"
+               android:viewName="pencil"
+            />
+    <ImageView android:id="@+id/scissors"
+               android:layout_height="wrap_content"
+               android:layout_width="wrap_content"
+               android:scaleType="centerCrop"
+               android:src="@drawable/scissors"
+               android:layout_column="1"
+               android:layout_row="3"
+               android:onClick="clicked"
+               android:viewName="scissors"
+            />
+</GridLayout>
\ No newline at end of file
diff --git a/samples/ApiDemos/res/layout/image_details.xml b/samples/ApiDemos/res/layout/image_details.xml
new file mode 100644
index 0000000..a176ce5
--- /dev/null
+++ b/samples/ApiDemos/res/layout/image_details.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:layout_width="match_parent"
+             android:layout_height="match_parent"
+             android:orientation="vertical"
+        >
+    <ImageView android:id="@+id/titleImage"
+               android:layout_height="0px"
+               android:layout_weight="1"
+               android:layout_width="match_parent"
+               android:scaleType="centerCrop"
+               android:viewName="hero"
+               android:onClick="clicked"
+            />
+    <LinearLayout android:layout_height="0px"
+                  android:layout_width="match_parent"
+                  android:layout_weight="2"
+                  android:orientation="vertical"
+            >
+        <View android:layout_width="match_parent"
+              android:layout_height="2dp"
+              android:background="#808080"/>
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="match_parent"
+                  android:text="Ducky"
+                  android:textSize="30sp"
+                  android:textColor="#FFF"
+                />
+        <View android:layout_width="match_parent"
+              android:layout_height="2dp"
+              android:background="#808080"/>
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="match_parent"
+                  android:text="Woot!"
+                  android:textSize="30sp"
+                  android:textColor="#FFF"
+                />
+        <View android:layout_width="match_parent"
+              android:layout_height="2dp"
+              android:background="#808080"/>
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="match_parent"
+                  android:text="Ball"
+                  android:textSize="30sp"
+                  android:textColor="#FFF"
+                />
+        <View android:layout_width="match_parent"
+              android:layout_height="2dp"
+              android:background="#808080"/>
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="match_parent"
+                  android:text="Block"
+                  android:textSize="30sp"
+                  android:textColor="#FFF"
+                />
+        <View android:layout_width="match_parent"
+              android:layout_height="2dp"
+              android:background="#808080"/>
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="match_parent"
+                  android:text="Jelly Bean"
+                  android:textSize="30sp"
+                  android:textColor="#FFF"
+                />
+        <View android:layout_width="match_parent"
+              android:layout_height="2dp"
+              android:background="#808080"/>
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="match_parent"
+                  android:text="Mug"
+                  android:textSize="30sp"
+                  android:textColor="#FFF"
+                />
+        <View android:layout_width="match_parent"
+              android:layout_height="2dp"
+              android:background="#808080"/>
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="match_parent"
+                  android:text="Pencil"
+                  android:textSize="30sp"
+                  android:textColor="#FFF"
+                />
+        <View android:layout_width="match_parent"
+              android:layout_height="2dp"
+              android:background="#808080"/>
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="match_parent"
+                  android:text="Scissors"
+                  android:textSize="30sp"
+                  android:textColor="#FFF"
+                />
+
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/ApiDemos/res/layout/image_switcher_1.xml b/samples/ApiDemos/res/layout/image_switcher_1.xml
deleted file mode 100644
index 0fdf3f9..0000000
--- a/samples/ApiDemos/res/layout/image_switcher_1.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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.
--->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
-    android:layout_width="match_parent" 
-    android:layout_height="match_parent"> 
-    
-    <ImageSwitcher android:id="@+id/switcher"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_alignParentTop="true"
-        android:layout_alignParentLeft="true"
-    />
-    
-    <Gallery android:id="@+id/gallery"
-        android:background="#55000000"
-        android:layout_width="match_parent"
-        android:layout_height="60dp"
-        android:layout_alignParentBottom="true"
-        android:layout_alignParentLeft="true"
-        
-        android:gravity="center_vertical"
-        android:spacing="16dp"
-    />
-
-</RelativeLayout>
-   
diff --git a/samples/ApiDemos/res/layout/path_animations.xml b/samples/ApiDemos/res/layout/path_animations.xml
new file mode 100644
index 0000000..93abc98
--- /dev/null
+++ b/samples/ApiDemos/res/layout/path_animations.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+    <ScrollView android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+        <RadioGroup android:orientation="horizontal"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/path_animation_type"
+                >
+            <RadioButton android:id="@+id/named_components"
+                         android:layout_width="wrap_content"
+                         android:layout_height="wrap_content"
+                         android:text="Named Components"/>
+            <RadioButton android:id="@+id/property_components"
+                         android:layout_width="wrap_content"
+                         android:layout_height="wrap_content"
+                         android:text="Property Components"/>
+            <RadioButton android:id="@+id/multi_int"
+                         android:layout_width="wrap_content"
+                         android:layout_height="wrap_content"
+                         android:text="Multi-int"/>
+            <RadioButton android:id="@+id/multi_float"
+                         android:layout_width="wrap_content"
+                         android:layout_height="wrap_content"
+                         android:text="Multi-float"/>
+            <RadioButton android:id="@+id/named_setter"
+                         android:layout_width="wrap_content"
+                         android:layout_height="wrap_content"
+                         android:text="Named Property"/>
+            <RadioButton android:id="@+id/property_setter"
+                         android:layout_width="wrap_content"
+                         android:layout_height="wrap_content"
+                         android:text="Property"/>
+        </RadioGroup>
+    </ScrollView>
+    <view class="com.example.android.apis.animation.PathAnimations$CanvasView"
+          android:id="@+id/canvas"
+          android:layout_width="match_parent"
+          android:layout_height="0px"
+          android:layout_weight="1">
+        <ImageView android:id="@+id/moved_item"
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:src="@drawable/frog"/>
+    </view>
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/ApiDemos/res/transition/activity_transition_mgr.xml b/samples/ApiDemos/res/transition/activity_transition_mgr.xml
new file mode 100644
index 0000000..f1f461b
--- /dev/null
+++ b/samples/ApiDemos/res/transition/activity_transition_mgr.xml
@@ -0,0 +1,17 @@
+<?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.
+-->
+<transitionManager xmlns:android="http://schemas.android.com/apk/res/android">
+</transitionManager>
diff --git a/samples/ApiDemos/res/transition/explode.xml b/samples/ApiDemos/res/transition/explode.xml
new file mode 100644
index 0000000..bb93ca7
--- /dev/null
+++ b/samples/ApiDemos/res/transition/explode.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.
+-->
+<!-- BEGIN_INCLUDE(Explode) -->
+<explode/>
+<!-- END_INCLUDE(Explode) -->
diff --git a/samples/ApiDemos/res/transition/explode_move_together.xml b/samples/ApiDemos/res/transition/explode_move_together.xml
new file mode 100644
index 0000000..80c6827
--- /dev/null
+++ b/samples/ApiDemos/res/transition/explode_move_together.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+<!-- BEGIN_INCLUDE(MultipleTransform) -->
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
+    <explode/>
+    <transitionSet>
+        <targets>
+            <target android:excludeClass="android.widget.ImageView"/>
+        </targets>
+        <changeBounds/>
+        <changeTransform/>
+        <changeClipBounds/>
+    </transitionSet>
+    <moveImage>
+        <targets>
+            <target android:targetClass="android.widget.ImageView"/>
+        </targets>
+    </moveImage>
+</transitionSet>
+<!-- END_INCLUDE(MultipleTransform) -->
diff --git a/samples/ApiDemos/res/transition/move_image.xml b/samples/ApiDemos/res/transition/move_image.xml
new file mode 100644
index 0000000..28bdf4e
--- /dev/null
+++ b/samples/ApiDemos/res/transition/move_image.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.
+-->
+<!-- BEGIN_INCLUDE(MoveImage) -->
+<moveImage/>
+<!-- END_INCLUDE(MoveImage) -->
diff --git a/samples/ApiDemos/res/values-v11/styles.xml b/samples/ApiDemos/res/values-v11/styles.xml
index 3b4fead..5b92c33 100644
--- a/samples/ApiDemos/res/values-v11/styles.xml
+++ b/samples/ApiDemos/res/values-v11/styles.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!--
+     Copyright (C) 2011 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.
@@ -15,15 +16,17 @@
 -->
 
 <resources>
-    <!-- For API level 11 or later, the Holo theme is available and we prefer that. -->
-    <style name="ThemeHolo" parent="android:Theme.Holo">
-    </style>
 
     <!-- For API level 11 or later, the Holo theme is available and we prefer that. -->
-    <style name="ThemeHoloDialog" parent="android:Theme.Holo.Dialog">
-    </style>
+    <style name="ThemeCurrent" parent="@android:Theme.Holo" />
+
+    <!-- For API level 11 or later, the Holo theme is available and we prefer that. -->
+    <style name="ThemeCurrentDialog" parent="@android:Theme.Holo.Dialog" />
 
     <!-- For API level 11 or later, we can use the magical DialogWhenLarge theme. -->
-    <style name="ThemeDialogWhenLarge" parent="android:style/Theme.Holo.DialogWhenLarge">
-    </style>
-</resources>
+    <style name="ThemeDialogWhenLarge" parent="@android:style/Theme.Holo.DialogWhenLarge" />
+
+    <!-- For API level 11 or later, the Holo theme is available and we prefer that. -->
+    <style name="ThemeDefault" parent="@android:style/Theme.Holo" />
+
+</resources>
\ No newline at end of file
diff --git a/samples/ApiDemos/res/values-v14/styles.xml b/samples/ApiDemos/res/values-v14/styles.xml
new file mode 100644
index 0000000..39e5290
--- /dev/null
+++ b/samples/ApiDemos/res/values-v14/styles.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2011 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>
+
+    <!-- For API level 14 or later, the DeviceDefault theme is available and we prefer that. -->
+    <style name="ThemeDefault" parent="@android:style/Theme.DeviceDefault" />
+
+</resources>
\ No newline at end of file
diff --git a/samples/ApiDemos/res/values-v19/styles.xml b/samples/ApiDemos/res/values-v19/styles.xml
new file mode 100644
index 0000000..c0bd00b
--- /dev/null
+++ b/samples/ApiDemos/res/values-v19/styles.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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>
+    <!-- For API level XX or later, the Quantum theme is available and we prefer that. -->
+    <style name="ThemeCurrent" parent="android:Theme.Quantum">
+    </style>
+
+    <!-- For API level XX or later, the Holo theme is available and we prefer that. -->
+    <style name="ThemeCurrentDialog" parent="android:Theme.Quantum.Dialog">
+    </style>
+
+    <!-- For API level XX or later, we can use the magical DialogWhenLarge theme. -->
+    <style name="ThemeCurrentDialogWhenLarge" parent="android:style/Theme.Quantum.DialogWhenLarge">
+    </style>
+</resources>
diff --git a/samples/ApiDemos/res/values-v20/bools.xml b/samples/ApiDemos/res/values-v20/bools.xml
new file mode 100644
index 0000000..3a4b91e
--- /dev/null
+++ b/samples/ApiDemos/res/values-v20/bools.xml
@@ -0,0 +1,22 @@
+<?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>
+    <!-- This resource is true if running under at least L-Release
+         API level.  The default value is false; an alternative value
+         for L-Release is true. -->
+    <bool name="atLeastLRelease">true</bool>
+</resources>
diff --git a/samples/ApiDemos/res/values-v20/styles.xml b/samples/ApiDemos/res/values-v20/styles.xml
new file mode 100644
index 0000000..e454942
--- /dev/null
+++ b/samples/ApiDemos/res/values-v20/styles.xml
@@ -0,0 +1,29 @@
+<?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>
+    <!-- For API level XX or later, the Quantum theme is available and we prefer that. -->
+    <style name="ThemeCurrent" parent="android:Theme.Quantum.Light">
+    </style>
+
+    <!-- For API level XX or later, the Holo theme is available and we prefer that. -->
+    <style name="ThemeCurrentDialog" parent="android:Theme.Quantum.Light.Dialog">
+    </style>
+
+    <!-- For API level XX or later, we can use the magical DialogWhenLarge theme. -->
+    <style name="ThemeCurrentDialogWhenLarge" parent="android:style/Theme.Quantum.Light.DialogWhenLarge">
+    </style>
+</resources>
diff --git a/samples/ApiDemos/res/values/attrs.xml b/samples/ApiDemos/res/values/attrs.xml
index bf33788..558f3ef 100644
--- a/samples/ApiDemos/res/values/attrs.xml
+++ b/samples/ApiDemos/res/values/attrs.xml
@@ -21,12 +21,6 @@
         <attr name="android:preferenceLayoutChild" />
     </declare-styleable>
     
-    <!-- These are the attributes that we want to retrieve from the theme
-         in view/Gallery1.java -->
-    <declare-styleable name="Gallery1">
-        <attr name="android:galleryItemBackground" />
-    </declare-styleable>
-    
      <declare-styleable name="LabelView">
         <attr name="text" format="string" />
         <attr name="textColor" format="color" />
diff --git a/samples/ApiDemos/res/values/bools.xml b/samples/ApiDemos/res/values/bools.xml
index fa3f25f..127c142 100644
--- a/samples/ApiDemos/res/values/bools.xml
+++ b/samples/ApiDemos/res/values/bools.xml
@@ -49,4 +49,9 @@
          for KitKat is true. -->
     <bool name="atLeastKitKat">false</bool>
 
+    <!-- This resource is true if running under at least L-Release
+         API level.  The default value is false; an alternative value
+         for L-Release is true. -->
+    <bool name="atLeastLRelease">false</bool>
+
 </resources>
diff --git a/samples/ApiDemos/res/values/colors.xml b/samples/ApiDemos/res/values/colors.xml
index f2534d1..147ba84 100644
--- a/samples/ApiDemos/res/values/colors.xml
+++ b/samples/ApiDemos/res/values/colors.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
+<!--
+     Copyright (C) 2007 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.
@@ -15,12 +16,12 @@
 -->
 
 <resources>
+
     <drawable name="red">#7f00</drawable>
     <drawable name="blue">#770000ff</drawable>
     <drawable name="green">#7700ff00</drawable>
-	<drawable name="yellow">#77ffff00</drawable>
-	
-	<drawable name="screen_background_black">#ff000000</drawable>
+    <drawable name="yellow">#77ffff00</drawable>
+    <drawable name="screen_background_black">#ff000000</drawable>
     <drawable name="translucent_background">#e0000000</drawable>
     <drawable name="transparent_background">#00000000</drawable>
 
@@ -28,5 +29,10 @@
     <color name="solid_blue">#0000ff</color>
     <color name="solid_green">#f0f0</color>
     <color name="solid_yellow">#ffffff00</color>
+    <color name="purply">#ff884488</color>
+
+    <!-- A custom theme that is a variation on the light them with a different
+         background color. -->
+    <color name="custom_theme_color">#b0b0ff</color>
 
 </resources>
diff --git a/samples/ApiDemos/res/values/strings.xml b/samples/ApiDemos/res/values/strings.xml
index 804087d..46ef1a2 100644
--- a/samples/ApiDemos/res/values/strings.xml
+++ b/samples/ApiDemos/res/values/strings.xml
@@ -463,6 +463,8 @@
     <string name="ir_send">Send IR</string>
     <string name="ir_get_freqs">Get Carrier Frequencies</string>
 
+    <string name="activity_documents">Content/Storage/Documents</string>
+
     <!-- ============================== -->
     <!--  app/intents examples strings     -->
     <!-- ============================== -->
@@ -741,10 +743,19 @@
     <string name="disable_camera">Disable all device cameras</string>
     <string name="disable_keyguard_widgets">Disable keyguard widgets</string>
     <string name="disable_keyguard_secure_camera">Disable keyguard secure camera</string>
+    <string name="disable_keyguard_notifications">Disable keyguard notifications</string>
+    <string name="disable_keyguard_unredacted_notifications">Disable keyguard unredacted notifications</string>
+    <string name="disable_keyguard_trust_agents">Disable keyguard Trust Agents</string>
     <string name="keyguard_widgets_disabled">Keyguard widgets disabled</string>
     <string name="keyguard_widgets_enabled">Keyguard widgets enabled</string>
     <string name="keyguard_secure_camera_disabled">Keyguard secure camera disabled</string>
     <string name="keyguard_secure_camera_enabled">Keyguard secure camera enabled</string>
+    <string name="keyguard_secure_notifications_disabled">Keyguard notifications disabled</string>
+    <string name="keyguard_secure_notifications_enabled">Keyguard notifications enabled</string>
+    <string name="keyguard_unredacted_notifications_disabled">Keyguard unredacted notifications disabled</string>
+    <string name="keyguard_unredacted_notifications_enabled">Keyguard unredacted notifications enabled</string>
+    <string name="keyguard_trust_agents_disabled">Keyguard Trust Agents disabled</string>
+    <string name="keyguard_trust_agents_enabled">Keyguard Trust Agents enabled</string>
     <string name="camera_disabled">Device cameras disabled</string>
     <string name="camera_enabled">Device cameras enabled</string>
     <string name="password_controls_category">Password controls</string>
@@ -1116,7 +1127,6 @@
     <string name="focus_5_button3">3</string>
     <string name="focus_5_button4">4</string>
     <string name="focus_5_button5">5</string>
-    <string name="gallery_2_text">Testing</string>
     <string name="grid_layout_1_instructions">Type here:</string>
     <string name="grid_layout_1_ok">Ok</string>
     <string name="grid_layout_1_cancel">Cancel</string>
diff --git a/samples/ApiDemos/res/values/styles.xml b/samples/ApiDemos/res/values/styles.xml
index 49a1c25..6c63d54 100644
--- a/samples/ApiDemos/res/values/styles.xml
+++ b/samples/ApiDemos/res/values/styles.xml
@@ -15,9 +15,6 @@
 -->
 
 <resources>
-    <!-- A custom theme that is a variation on the light them with a different
-         background color. -->
-    <color name="custom_theme_color">#b0b0ff</color>
     <style name="CustomTheme" parent="android:Theme.Light">
         <item name="android:windowBackground">@color/custom_theme_color</item>
         <item name="android:colorBackground">@color/custom_theme_color</item>
@@ -26,24 +23,33 @@
     <!-- This is a theme that will adjust itself depending on the API version.
          The default definition is the safe one, using a theme that has always
          been defined.  Look at values-11/styles.xml for a variation that is
-         selected when the holographic theme is available. -->
-    <style name="ThemeHolo" parent="android:Theme">
-    </style>
+         selected when the holographic theme is available, or look at
+         values-XX/styles.xml for a variation that is selected when the quantum
+         theme is available. -->
+    <style name="ThemeCurrent" parent="android:Theme" />
+
+    <!-- This is a theme that reflects the default theme used when no theme is
+         specified by an application or activity. In API 14 and above, this
+         refers to the DeviceDefault theme. -->
+    <style name="ThemeDefault" parent="android:Theme" />
 
     <!-- This is a theme that will adjust itself depending on the API version.
          The default definition is the safe one, using a theme that has always
          been defined.  Look at values-11/styles.xml for a variation that is
-         selected when the holographic theme is available. -->
-    <style name="ThemeHoloDialog" parent="android:Theme.Dialog">
-    </style>
+         selected when the holographic theme is available, or look at
+         values-XX/styles.xml for a variation that is selected when the quantum
+         theme is available. -->
+    <style name="ThemeCurrentDialog" parent="android:Theme.Dialog" />
+
+    <!-- Older platforms don't have Theme.Holo.DialogWhenLarge; we will define
+         our own wrapper theme that uses it only when running on the appropriate
+         platform version.  On older platforms, we always use the generic
+         fullscreen theme, because they don't support some feature that help
+         in correctly laying out an activity as a dialog. -->
+    <style name="ThemeCurrentDialogWhenLarge" parent="android:style/Theme" />
 
     <!-- Base application theme is the default theme. -->
-    <style name="Theme" parent="android:Theme">
-    </style>
-
-    <!-- Base application theme is the default theme. -->
-    <style name="BadTheme" parent="@android:style/Theme.Holo.Light.NoActionBar">
-    </style>
+    <style name="Theme" parent="android:Theme" />
 
     <!-- Variation on our application theme that forces a plain
         text style. -->
@@ -91,14 +97,6 @@
         <item name="android:windowNoTitle">true</item>
         <item name="android:colorForeground">#fff</item>
     </style>
-    
-    <!-- Older platforms don't have Theme.Holo.DialogWhenLarge; we will define
-         our own wrapper theme that uses it only when running on the appropriate
-         platform version.  On older platforms, we always use the generic
-         fullscreen theme, because they don't support some feature that help
-         in correctly laying out an activity as a dialog. -->
-    <style name="ThemeDialogWhenLarge" parent="android:style/Theme">
-    </style>
 
     <style name="TextAppearance.Theme.PlainText" parent="android:TextAppearance.Theme">
         <item name="android:textStyle">normal</item>
@@ -121,4 +119,15 @@
         <item name="android:layout_width">wrap_content</item>
         <item name="android:layout_height">wrap_content</item>
     </style>
+
+    <style name="ActivityTransitionTheme" parent="android:Theme.Quantum">
+	<item name="android:windowEnterTransition">@transition/explode</item>
+	<item name="android:windowExitTransition">@transition/explode</item>
+	<item name="android:windowSharedElementEnterTransition">@transition/move_image</item>
+	<item name="android:windowSharedElementExitTransition">@transition/move_image</item>
+	<item name="android:windowAllowExitTransitionOverlap">true</item>
+	<item name="android:windowAllowEnterTransitionOverlap">false</item>
+        <item name="android:windowContentTransitions">true</item>
+    </style>
+
 </resources>
diff --git a/samples/ApiDemos/res/xml/device_admin_general.xml b/samples/ApiDemos/res/xml/device_admin_general.xml
index 3a1dd45..cfd0048 100644
--- a/samples/ApiDemos/res/xml/device_admin_general.xml
+++ b/samples/ApiDemos/res/xml/device_admin_general.xml
@@ -43,6 +43,18 @@
             android:key="key_disable_keyguard_secure_camera"
             android:title="@string/disable_keyguard_secure_camera" />
 
+        <CheckBoxPreference
+            android:key="key_disable_notifications"
+            android:title="@string/disable_keyguard_notifications" />
+
+        <CheckBoxPreference
+            android:key="key_disable_unredacted"
+            android:title="@string/disable_keyguard_unredacted_notifications" />
+
+        <CheckBoxPreference
+            android:key="key_disable_trust_agents"
+            android:title="@string/disable_keyguard_trust_agents" />
+
     </PreferenceCategory>
 
 </PreferenceScreen>
diff --git a/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransition.java b/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransition.java
new file mode 100644
index 0000000..8a72087
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransition.java
@@ -0,0 +1,132 @@
+/*
+ * 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.apis.animation;
+
+import com.example.android.apis.R;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.app.SharedElementListener;
+import android.content.Intent;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ImageView;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ */
+public class ActivityTransition extends Activity {
+
+    private static final String TAG = "ActivityTransition";
+
+    private static final String KEY_ID = "ViewTransitionValues:id";
+
+    private ImageView mHero;
+
+    public static final int[] DRAWABLES = {
+            R.drawable.ball,
+            R.drawable.block,
+            R.drawable.ducky,
+            R.drawable.jellies,
+            R.drawable.mug,
+            R.drawable.pencil,
+            R.drawable.scissors,
+            R.drawable.woot,
+    };
+
+    public static final int[] IDS = {
+            R.id.ball,
+            R.id.block,
+            R.id.ducky,
+            R.id.jellies,
+            R.id.mug,
+            R.id.pencil,
+            R.id.scissors,
+            R.id.woot,
+    };
+
+    public static final String[] NAMES = {
+            "ball",
+            "block",
+            "ducky",
+            "jellies",
+            "mug",
+            "pencil",
+            "scissors",
+            "woot",
+    };
+
+    public static int getIdForKey(String id) {
+        return IDS[getIndexForKey(id)];
+    }
+
+    public static int getDrawableIdForKey(String id) {
+        return DRAWABLES[getIndexForKey(id)];
+    }
+
+    public static int getIndexForKey(String id) {
+        for (int i = 0; i < NAMES.length; i++) {
+            String name = NAMES[i];
+            if (name.equals(id)) {
+                return i;
+            }
+        }
+        return 2;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().setBackgroundDrawable(new ColorDrawable(randomColor()));
+        setContentView(R.layout.image_block);
+        setupHero();
+    }
+
+    private void setupHero() {
+        String name = getIntent().getStringExtra(KEY_ID);
+        mHero = null;
+        if (name != null) {
+            mHero = (ImageView) findViewById(getIdForKey(name));
+            setSharedElementListener(new SharedElementListener() {
+                @Override
+                public void remapSharedElements(List<String> names,
+                        Map<String, View> sharedElements) {
+                    sharedElements.put("hero", mHero);
+                }
+            });
+        }
+    }
+
+    public void clicked(View v) {
+        mHero = (ImageView) v;
+        Intent intent = new Intent(this, ActivityTransitionDetails.class);
+        intent.putExtra(KEY_ID, v.getViewName());
+        ActivityOptions activityOptions
+                = ActivityOptions.makeSceneTransitionAnimation(this, mHero, "hero");
+        startActivity(intent, activityOptions.toBundle());
+    }
+
+    private static int randomColor() {
+        int red = (int)(Math.random() * 128);
+        int green = (int)(Math.random() * 128);
+        int blue = (int)(Math.random() * 128);
+        return 0xFF000000 | (red << 16) | (green << 8) | blue;
+    }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransitionDetails.java b/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransitionDetails.java
new file mode 100644
index 0000000..e657c55
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransitionDetails.java
@@ -0,0 +1,75 @@
+/*
+ * 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.apis.animation;
+
+import com.example.android.apis.R;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ImageView;
+
+/**
+ *
+ */
+public class ActivityTransitionDetails extends Activity {
+
+    private static final String TAG = "ActivityTransitionDetails";
+
+    private static final String KEY_ID = "ViewTransitionValues:id";
+
+    private int mImageResourceId = R.drawable.ducky;
+
+    private String mName = "ducky";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().setBackgroundDrawable(new ColorDrawable(randomColor()));
+        setContentView(R.layout.image_details);
+        ImageView titleImage = (ImageView) findViewById(R.id.titleImage);
+        titleImage.setImageDrawable(getHeroDrawable());
+    }
+
+    private Drawable getHeroDrawable() {
+        String name = getIntent().getStringExtra(KEY_ID);
+        if (name != null) {
+            mName = name;
+            mImageResourceId = ActivityTransition.getDrawableIdForKey(name);
+        }
+
+        return getResources().getDrawable(mImageResourceId);
+    }
+
+    public void clicked(View v) {
+        Intent intent = new Intent(this, ActivityTransition.class);
+        intent.putExtra(KEY_ID, mName);
+        ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(this,
+                v, "hero");
+        startActivity(intent, activityOptions.toBundle());
+    }
+
+    private static int randomColor() {
+        int red = (int)(Math.random() * 128);
+        int green = (int)(Math.random() * 128);
+        int blue = (int)(Math.random() * 128);
+        return 0xFF000000 | (red << 16) | (green << 8) | blue;
+    }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/animation/PathAnimations.java b/samples/ApiDemos/src/com/example/android/apis/animation/PathAnimations.java
new file mode 100644
index 0000000..daa8d99
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/animation/PathAnimations.java
@@ -0,0 +1,257 @@
+/*
+ * 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.apis.animation;
+
+import android.animation.ObjectAnimator;
+import android.animation.TypeConverter;
+import android.animation.ValueAnimator;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.RectF;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.util.FloatMath;
+import android.util.Log;
+import android.util.Property;
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.LinearInterpolator;
+import android.widget.FrameLayout;
+import android.widget.RadioGroup;
+
+import com.example.android.apis.R;
+
+/** This application demonstrates the use of Path animation. */
+public class PathAnimations extends Activity implements
+        RadioGroup.OnCheckedChangeListener, View.OnLayoutChangeListener {
+
+    final static Path sTraversalPath = new Path();
+    final static float TRAVERSE_PATH_SIZE = 7.0f;
+
+    final static Property<PathAnimations, Point> POINT_PROPERTY
+            = new Property<PathAnimations, Point>(Point.class, "point") {
+        @Override
+        public Point get(PathAnimations object) {
+            View v = object.findViewById(R.id.moved_item);
+            return new Point(Math.round(v.getX()), Math.round(v.getY()));
+        }
+
+        @Override
+        public void set(PathAnimations object, Point value) {
+            object.setCoordinates(value.x, value.y);
+        }
+    };
+
+    static {
+        float inverse_sqrt8 = FloatMath.sqrt(0.125f);
+        RectF bounds = new RectF(1, 1, 3, 3);
+        sTraversalPath.addArc(bounds, 45, 180);
+        sTraversalPath.addArc(bounds, 225, 180);
+
+        bounds.set(1.5f + inverse_sqrt8, 1.5f + inverse_sqrt8, 2.5f + inverse_sqrt8,
+                2.5f + inverse_sqrt8);
+        sTraversalPath.addArc(bounds, 45, 180);
+        sTraversalPath.addArc(bounds, 225, 180);
+
+        bounds.set(4, 1, 6, 3);
+        sTraversalPath.addArc(bounds, 135, -180);
+        sTraversalPath.addArc(bounds, -45, -180);
+
+        bounds.set(4.5f - inverse_sqrt8, 1.5f + inverse_sqrt8, 5.5f - inverse_sqrt8, 2.5f + inverse_sqrt8);
+        sTraversalPath.addArc(bounds, 135, -180);
+        sTraversalPath.addArc(bounds, -45, -180);
+
+        sTraversalPath.addCircle(3.5f, 3.5f, 0.5f, Path.Direction.CCW);
+
+        sTraversalPath.addArc(new RectF(1, 2, 6, 6), 0, 180);
+    }
+
+    private CanvasView mCanvasView;
+
+    private ObjectAnimator mAnimator;
+
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.path_animations);
+        mCanvasView = (CanvasView) findViewById(R.id.canvas);
+        mCanvasView.addOnLayoutChangeListener(this);
+        ((RadioGroup) findViewById(R.id.path_animation_type)).setOnCheckedChangeListener(this);
+    }
+
+    public void setCoordinates(int x, int y) {
+        changeCoordinates((float) x, (float) y);
+    }
+
+    public void changeCoordinates(float x, float y) {
+        View v = findViewById(R.id.moved_item);
+        v.setX(x);
+        v.setY(y);
+    }
+
+    public void setPoint(PointF point) {
+        changeCoordinates(point.x, point.y);
+    }
+
+    @Override
+    public void onCheckedChanged(RadioGroup group, int checkedId) {
+        startAnimator(checkedId);
+    }
+
+    @Override
+    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+            int oldTop, int oldRight, int oldBottom) {
+        int checkedId = ((RadioGroup)findViewById(R.id.path_animation_type)).getCheckedRadioButtonId();
+        if (checkedId != RadioGroup.NO_ID) {
+            startAnimator(checkedId);
+        }
+    }
+
+    private void startAnimator(int checkedId) {
+        if (mAnimator != null) {
+            mAnimator.cancel();
+            mAnimator = null;
+        }
+
+        View view = findViewById(R.id.moved_item);
+        Path path = mCanvasView.getPath();
+        if (path.isEmpty()) {
+            return;
+        }
+
+        switch (checkedId) {
+            case R.id.named_components:
+                // Use the named "x" and "y" properties for individual (x, y)
+                // coordinates of the Path and set them on the view object.
+                // The setX(float) and setY(float) methods are called on view.
+                // An int version of this method also exists for animating
+                // int Properties.
+                mAnimator = ObjectAnimator.ofFloat(view, "x", "y", path);
+                break;
+            case R.id.property_components:
+                // Use two Properties for individual (x, y) coordinates of the Path
+                // and set them on the view object.
+                // An int version of this method also exists for animating
+                // int Properties.
+                mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path);
+                break;
+            case R.id.multi_int:
+                // Use a multi-int setter to animate along a Path. The method
+                // setCoordinates(int x, int y) is called on this during the animation.
+                // Either "setCoordinates" or "coordinates" are acceptable parameters
+                // because the "set" can be implied.
+                mAnimator = ObjectAnimator.ofMultiInt(this, "setCoordinates", path);
+                break;
+            case R.id.multi_float:
+                // Use a multi-float setter to animate along a Path. The method
+                // changeCoordinates(float x, float y) is called on this during the animation.
+                mAnimator = ObjectAnimator.ofMultiFloat(this, "changeCoordinates", path);
+                break;
+            case R.id.named_setter:
+                // Use the named "point" property to animate along the Path.
+                // There must be a method setPoint(PointF) on the animated object.
+                // Because setPoint takes a PointF parameter, no TypeConverter is necessary.
+                // In this case, the animated object is PathAnimations.
+                mAnimator = ObjectAnimator.ofObject(this, "point", null, path);
+                break;
+            case R.id.property_setter:
+                // Use the POINT_PROPERTY property to animate along the Path.
+                // POINT_PROPERTY takes a Point, not a PointF, so the TypeConverter
+                // PointFToPointConverter is necessary.
+                mAnimator = ObjectAnimator.ofObject(this, POINT_PROPERTY,
+                        new PointFToPointConverter(), path);
+                break;
+        }
+
+        mAnimator.setDuration(10000);
+        mAnimator.setRepeatMode(Animation.RESTART);
+        mAnimator.setRepeatCount(ValueAnimator.INFINITE);
+        mAnimator.setInterpolator(new LinearInterpolator());
+        mAnimator.start();
+    }
+
+    public static class CanvasView extends FrameLayout {
+
+        Path mPath = new Path();
+
+        Paint mPathPaint = new Paint();
+
+        public CanvasView(Context context) {
+            super(context);
+            init();
+        }
+
+        public CanvasView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+            init();
+        }
+
+        public CanvasView(Context context, AttributeSet attrs, int defStyle) {
+            super(context, attrs, defStyle);
+            init();
+        }
+
+        private void init() {
+            setWillNotDraw(false);
+            mPathPaint.setColor(0xFFFF0000);
+            mPathPaint.setStrokeWidth(2.0f);
+            mPathPaint.setStyle(Paint.Style.STROKE);
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+            super.onLayout(changed, left, top, right, bottom);
+            if (changed) {
+                Matrix scale = new Matrix();
+                float scaleWidth = (right-left)/TRAVERSE_PATH_SIZE;
+                float scaleHeight= (bottom-top)/TRAVERSE_PATH_SIZE;
+                scale.setScale(scaleWidth, scaleHeight);
+                sTraversalPath.transform(scale, mPath);
+            }
+        }
+
+        public Path getPath() {
+            return mPath;
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            canvas.drawPath(mPath, mPathPaint);
+            super.draw(canvas);
+        }
+    }
+
+    private static class PointFToPointConverter extends TypeConverter<PointF, Point> {
+        Point mPoint = new Point();
+
+        public PointFToPointConverter() {
+            super(PointF.class, Point.class);
+        }
+
+        @Override
+        public Point convert(PointF value) {
+            mPoint.set(Math.round(value.x), Math.round(value.y));
+            return mPoint;
+        }
+    }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java b/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java
index db50185..a27dcdf 100644
--- a/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java
+++ b/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java
@@ -68,6 +68,9 @@
     // The following keys are used to find each preference item
     private static final String KEY_ENABLE_ADMIN = "key_enable_admin";
     private static final String KEY_DISABLE_CAMERA = "key_disable_camera";
+    private static final String KEY_DISABLE_NOTIFICATIONS = "key_disable_notifications";
+    private static final String KEY_DISABLE_UNREDACTED = "key_disable_unredacted";
+    private static final String KEY_DISABLE_TRUST_AGENTS = "key_disable_trust_agents";
     private static final String KEY_DISABLE_KEYGUARD_WIDGETS = "key_disable_keyguard_widgets";
     private static final String KEY_DISABLE_KEYGUARD_SECURE_CAMERA
             = "key_disable_keyguard_secure_camera";
@@ -128,6 +131,11 @@
         return mDPM.isAdminActive(mDeviceAdminSample);
     }
 
+    @Override
+    protected boolean isValidFragment(String fragmentName) {
+        return GeneralFragment.class.getName().equals(fragmentName);
+    }
+
     /**
      * Common fragment code for DevicePolicyManager access.  Provides two shared elements:
      *
@@ -250,6 +258,9 @@
         private CheckBoxPreference mDisableCameraCheckbox;
         private CheckBoxPreference mDisableKeyguardWidgetsCheckbox;
         private CheckBoxPreference mDisableKeyguardSecureCameraCheckbox;
+        private CheckBoxPreference mDisableKeyguardNotificationCheckbox;
+        private CheckBoxPreference mDisableKeyguardTrustAgentCheckbox;
+        private CheckBoxPreference mDisableKeyguardUnredactedCheckbox;
 
         @Override
         public void onCreate(Bundle savedInstanceState) {
@@ -257,14 +268,29 @@
             addPreferencesFromResource(R.xml.device_admin_general);
             mEnableCheckbox = (CheckBoxPreference) findPreference(KEY_ENABLE_ADMIN);
             mEnableCheckbox.setOnPreferenceChangeListener(this);
+
             mDisableCameraCheckbox = (CheckBoxPreference) findPreference(KEY_DISABLE_CAMERA);
             mDisableCameraCheckbox.setOnPreferenceChangeListener(this);
+
             mDisableKeyguardWidgetsCheckbox =
                 (CheckBoxPreference) findPreference(KEY_DISABLE_KEYGUARD_WIDGETS);
             mDisableKeyguardWidgetsCheckbox.setOnPreferenceChangeListener(this);
+
             mDisableKeyguardSecureCameraCheckbox =
                 (CheckBoxPreference) findPreference(KEY_DISABLE_KEYGUARD_SECURE_CAMERA);
             mDisableKeyguardSecureCameraCheckbox.setOnPreferenceChangeListener(this);
+
+            mDisableKeyguardNotificationCheckbox =
+                    (CheckBoxPreference) findPreference(KEY_DISABLE_NOTIFICATIONS);
+            mDisableKeyguardNotificationCheckbox.setOnPreferenceChangeListener(this);
+
+            mDisableKeyguardUnredactedCheckbox =
+                    (CheckBoxPreference) findPreference(KEY_DISABLE_UNREDACTED);
+            mDisableKeyguardUnredactedCheckbox.setOnPreferenceChangeListener(this);
+
+            mDisableKeyguardTrustAgentCheckbox =
+                    (CheckBoxPreference) findPreference(KEY_DISABLE_TRUST_AGENTS);
+            mDisableKeyguardTrustAgentCheckbox.setOnPreferenceChangeListener(this);
         }
 
         // At onResume time, reload UI with current values as required
@@ -287,6 +313,12 @@
                     DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL : 0;
             flags |= mDisableKeyguardSecureCameraCheckbox.isChecked() ?
                     DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA : 0;
+            flags |= mDisableKeyguardNotificationCheckbox.isChecked() ?
+                    DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS : 0;
+            flags |= mDisableKeyguardUnredactedCheckbox.isChecked() ?
+                    DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS : 0;
+            flags |= mDisableKeyguardTrustAgentCheckbox.isChecked() ?
+                    DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS : 0;
             return flags;
         }
 
@@ -317,7 +349,10 @@
                 mDPM.setCameraDisabled(mDeviceAdminSample, value);
                 reloadSummaries();
             } else if (preference == mDisableKeyguardWidgetsCheckbox
-                    || preference == mDisableKeyguardSecureCameraCheckbox) {
+                    || preference == mDisableKeyguardSecureCameraCheckbox
+                    || preference == mDisableKeyguardNotificationCheckbox
+                    || preference == mDisableKeyguardUnredactedCheckbox
+                    || preference == mDisableKeyguardTrustAgentCheckbox) {
                 mDPM.setKeyguardDisabledFeatures(mDeviceAdminSample, createKeyguardDisabledFlag());
                 reloadSummaries();
             }
@@ -342,6 +377,24 @@
                 (disabled & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0 ?
                 R.string.keyguard_secure_camera_disabled : R.string.keyguard_secure_camera_enabled);
             mDisableKeyguardSecureCameraCheckbox.setSummary(keyguardSecureCameraSummary);
+
+            String keyguardSecureNotificationsSummary = getString(
+                    (disabled & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) != 0 ?
+                        R.string.keyguard_secure_notifications_disabled
+                        : R.string.keyguard_secure_notifications_enabled);
+            mDisableKeyguardNotificationCheckbox.setSummary(keyguardSecureNotificationsSummary);
+
+            String keyguardUnredactedSummary = getString(
+                    (disabled & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) != 0
+                        ? R.string.keyguard_unredacted_notifications_disabled
+                        : R.string.keyguard_unredacted_notifications_enabled);
+            mDisableKeyguardUnredactedCheckbox.setSummary(keyguardUnredactedSummary);
+
+            String keyguardEnableTrustAgentSummary = getString(
+                    (disabled & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0 ?
+                        R.string.keyguard_trust_agents_disabled
+                        : R.string.keyguard_trust_agents_enabled);
+            mDisableKeyguardTrustAgentCheckbox.setSummary(keyguardEnableTrustAgentSummary);
         }
 
         /** Updates the device capabilities area (dis/enabling) as the admin is (de)activated */
@@ -349,6 +402,9 @@
             mDisableCameraCheckbox.setEnabled(enabled);
             mDisableKeyguardWidgetsCheckbox.setEnabled(enabled);
             mDisableKeyguardSecureCameraCheckbox.setEnabled(enabled);
+            mDisableKeyguardNotificationCheckbox.setEnabled(enabled);
+            mDisableKeyguardUnredactedCheckbox.setEnabled(enabled);
+            mDisableKeyguardTrustAgentCheckbox.setEnabled(enabled);
         }
     }
 
diff --git a/samples/ApiDemos/src/com/example/android/apis/content/DocumentsSample.java b/samples/ApiDemos/src/com/example/android/apis/content/DocumentsSample.java
new file mode 100644
index 0000000..544e637
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/content/DocumentsSample.java
@@ -0,0 +1,352 @@
+/*
+ * 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.apis.content;
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Example that exercises client side of {@link DocumentsContract}.
+ */
+public class DocumentsSample extends Activity {
+    private static final String TAG = "DocumentsSample";
+
+    private static final int CODE_READ = 42;
+    private static final int CODE_WRITE = 43;
+    private static final int CODE_PICK = 44;
+
+    private TextView mResult;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        final Context context = this;
+
+        final LinearLayout view = new LinearLayout(context);
+        view.setOrientation(LinearLayout.VERTICAL);
+
+        mResult = new TextView(context);
+        view.addView(mResult);
+
+        final CheckBox multiple = new CheckBox(context);
+        multiple.setText("ALLOW_MULTIPLE");
+        view.addView(multiple);
+        final CheckBox localOnly = new CheckBox(context);
+        localOnly.setText("LOCAL_ONLY");
+        view.addView(localOnly);
+
+        Button button;
+        button = new Button(context);
+        button.setText("OPEN_DOC */*");
+        button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
+                intent.setType("*/*");
+                if (multiple.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+                }
+                if (localOnly.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+                }
+                startActivityForResult(intent, CODE_READ);
+            }
+        });
+        view.addView(button);
+
+        button = new Button(context);
+        button.setText("OPEN_DOC image/*");
+        button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
+                intent.setType("image/*");
+                if (multiple.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+                }
+                if (localOnly.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+                }
+                startActivityForResult(intent, CODE_READ);
+            }
+        });
+        view.addView(button);
+
+        button = new Button(context);
+        button.setText("OPEN_DOC audio/ogg");
+        button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
+                intent.setType("audio/ogg");
+                if (multiple.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+                }
+                if (localOnly.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+                }
+                startActivityForResult(intent, CODE_READ);
+            }
+        });
+        view.addView(button);
+
+        button = new Button(context);
+        button.setText("OPEN_DOC text/plain, application/msword");
+        button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
+                intent.setType("*/*");
+                intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] {
+                        "text/plain", "application/msword" });
+                if (multiple.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+                }
+                if (localOnly.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+                }
+                startActivityForResult(intent, CODE_READ);
+            }
+        });
+        view.addView(button);
+
+        button = new Button(context);
+        button.setText("CREATE_DOC text/plain");
+        button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
+                intent.setType("text/plain");
+                intent.putExtra(Intent.EXTRA_TITLE, "foobar.txt");
+                if (localOnly.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+                }
+                startActivityForResult(intent, CODE_WRITE);
+            }
+        });
+        view.addView(button);
+
+        button = new Button(context);
+        button.setText("CREATE_DOC image/png");
+        button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
+                intent.setType("image/png");
+                intent.putExtra(Intent.EXTRA_TITLE, "mypicture.png");
+                if (localOnly.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+                }
+                startActivityForResult(intent, CODE_WRITE);
+            }
+        });
+        view.addView(button);
+
+        button = new Button(context);
+        button.setText("GET_CONTENT */*");
+        button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
+                intent.setType("*/*");
+                if (multiple.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+                }
+                if (localOnly.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+                }
+                startActivityForResult(Intent.createChooser(intent, "Kittens!"), CODE_READ);
+            }
+        });
+        view.addView(button);
+
+        button = new Button(context);
+        button.setText("PICK_DIRECTORY");
+        button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(Intent.ACTION_PICK_DIRECTORY);
+                if (localOnly.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+                }
+                startActivityForResult(Intent.createChooser(intent, "Kittens!"), CODE_PICK);
+            }
+        });
+        view.addView(button);
+
+        final ScrollView scroll = new ScrollView(context);
+        scroll.addView(view);
+
+        setContentView(scroll);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        final ContentResolver cr = getContentResolver();
+
+        clearLog();
+
+        log("resultCode=" + resultCode);
+        log("data=" + String.valueOf(data));
+
+        final Uri uri = data != null ? data.getData() : null;
+        if (uri != null) {
+            log("isDocumentUri=" + DocumentsContract.isDocumentUri(this, uri));
+        } else {
+            log("missing URI?");
+            return;
+        }
+
+        if (requestCode == CODE_READ) {
+            try {
+                cr.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+            } catch (SecurityException e) {
+                log("FAILED TO TAKE PERMISSION", e);
+            }
+            InputStream is = null;
+            try {
+                is = cr.openInputStream(uri);
+                log("read length=" + readFullyNoClose(is).length);
+            } catch (Exception e) {
+                log("FAILED TO READ", e);
+            } finally {
+                closeQuietly(is);
+            }
+        } else if (requestCode == CODE_WRITE) {
+            try {
+                cr.takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+            } catch (SecurityException e) {
+                log("FAILED TO TAKE PERMISSION", e);
+            }
+            OutputStream os = null;
+            try {
+                os = cr.openOutputStream(uri);
+                os.write("THE COMPLETE WORKS OF SHAKESPEARE".getBytes());
+                log("wrote data");
+            } catch (Exception e) {
+                log("FAILED TO WRITE", e);
+            } finally {
+                closeQuietly(os);
+            }
+        } else if (requestCode == CODE_PICK) {
+            // Find existing docs
+            Uri doc = DocumentsContract.buildDocumentViaUri(uri,
+                    DocumentsContract.getViaDocumentId(uri));
+            Uri child = DocumentsContract.buildChildDocumentsViaUri(uri,
+                    DocumentsContract.getViaDocumentId(uri));
+            Cursor c = cr.query(child, new String[] {
+                    Document.COLUMN_DISPLAY_NAME, Document.COLUMN_MIME_TYPE }, null, null, null);
+            try {
+                while (c.moveToNext()) {
+                    log("found child=" + c.getString(0) + ", mime=" + c.getString(1));
+                }
+            } finally {
+                closeQuietly(c);
+            }
+
+            // Create some documents
+            Uri pic = DocumentsContract.createDocument(cr, doc, "image/png", "pic.png");
+            Uri dir = DocumentsContract.createDocument(cr, doc, Document.MIME_TYPE_DIR, "my dir");
+            Uri dirPic = DocumentsContract.createDocument(cr, dir, "image/png", "pic2.png");
+
+            log("created " + pic);
+            log("created " + dir);
+            log("created " + dirPic);
+
+            // Write to one of them
+            OutputStream os = null;
+            try {
+                os = cr.openOutputStream(dirPic);
+                os.write("THE COMPLETE WORKS OF SHAKESPEARE".getBytes());
+                log("wrote data");
+            } catch (Exception e) {
+                log("FAILED TO WRITE", e);
+            } finally {
+                closeQuietly(os);
+            }
+
+            // And delete the first pic
+            if (DocumentsContract.deleteDocument(cr, pic)) {
+                log("deleted untouched pic");
+            } else {
+                log("FAILED TO DELETE PIC");
+            }
+        }
+    }
+
+    private void clearLog() {
+        mResult.setText(null);
+    }
+
+    private void log(String msg) {
+        log(msg, null);
+    }
+
+    private void log(String msg, Throwable t) {
+        Log.d(TAG, msg, t);
+        mResult.setText(mResult.getText() + "\n" + msg);
+    }
+
+    public static byte[] readFullyNoClose(InputStream in) throws IOException {
+        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+        byte[] buffer = new byte[1024];
+        int count;
+        while ((count = in.read(buffer)) != -1) {
+            bytes.write(buffer, 0, count);
+        }
+        return bytes.toByteArray();
+    }
+
+    public static void closeQuietly(AutoCloseable closeable) {
+        if (closeable != null) {
+            try {
+                closeable.close();
+            } catch (RuntimeException rethrown) {
+                throw rethrown;
+            } catch (Exception ignored) {
+            }
+        }
+    }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/os/Sensors.java b/samples/ApiDemos/src/com/example/android/apis/os/Sensors.java
deleted file mode 100644
index 9863222..0000000
--- a/samples/ApiDemos/src/com/example/android/apis/os/Sensors.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (C) 2007 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.apis.os;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
-import android.view.View;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.RectF;
-
-/**
- * <h3>Application that displays the values of the acceleration sensor graphically.</h3>
-
-<p>This demonstrates the {@link android.hardware.SensorManager android.hardware.SensorManager} class.
-
-<h4>Demo</h4>
-OS / Sensors
- 
-<h4>Source files</h4>
- * <table class="LinkTable">
- *         <tr>
- *             <td >src/com.example.android.apis/os/Sensors.java</td>
- *             <td >Sensors</td>
- *         </tr>
- * </table> 
- */
-public class Sensors extends Activity {
-    private SensorManager mSensorManager;
-    private GraphView mGraphView;
-
-    private class GraphView extends View implements SensorEventListener
-    {
-        private Bitmap  mBitmap;
-        private Paint   mPaint = new Paint();
-        private Canvas  mCanvas = new Canvas();
-        private Path    mPath = new Path();
-        private RectF   mRect = new RectF();
-        private float   mLastValues[] = new float[3*2];
-        private float   mOrientationValues[] = new float[3];
-        private int     mColors[] = new int[3*2];
-        private float   mLastX;
-        private float   mScale[] = new float[2];
-        private float   mYOffset;
-        private float   mMaxX;
-        private float   mSpeed = 1.0f;
-        private float   mWidth;
-        private float   mHeight;
-        
-        public GraphView(Context context) {
-            super(context);
-            mColors[0] = Color.argb(192, 255, 64, 64);
-            mColors[1] = Color.argb(192, 64, 128, 64);
-            mColors[2] = Color.argb(192, 64, 64, 255);
-            mColors[3] = Color.argb(192, 64, 255, 255);
-            mColors[4] = Color.argb(192, 128, 64, 128);
-            mColors[5] = Color.argb(192, 255, 255, 64);
-
-            mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
-            mRect.set(-0.5f, -0.5f, 0.5f, 0.5f);
-            mPath.arcTo(mRect, 0, 180);
-        }
-        
-        @Override
-        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-            mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
-            mCanvas.setBitmap(mBitmap);
-            mCanvas.drawColor(0xFFFFFFFF);
-            mYOffset = h * 0.5f;
-            mScale[0] = - (h * 0.5f * (1.0f / (SensorManager.STANDARD_GRAVITY * 2)));
-            mScale[1] = - (h * 0.5f * (1.0f / (SensorManager.MAGNETIC_FIELD_EARTH_MAX)));
-            mWidth = w;
-            mHeight = h;
-            if (mWidth < mHeight) {
-                mMaxX = w;
-            } else {
-                mMaxX = w-50;
-            }
-            mLastX = mMaxX;
-            super.onSizeChanged(w, h, oldw, oldh);
-        }
-
-        @Override
-        protected void onDraw(Canvas canvas) {
-            synchronized (this) {
-                if (mBitmap != null) {
-                    final Paint paint = mPaint;
-                    final Path path = mPath;
-                    final int outer = 0xFFC0C0C0;
-                    final int inner = 0xFFff7010;
-
-                    if (mLastX >= mMaxX) {
-                        mLastX = 0;
-                        final Canvas cavas = mCanvas;
-                        final float yoffset = mYOffset;
-                        final float maxx = mMaxX;
-                        final float oneG = SensorManager.STANDARD_GRAVITY * mScale[0];
-                        paint.setColor(0xFFAAAAAA);
-                        cavas.drawColor(0xFFFFFFFF);
-                        cavas.drawLine(0, yoffset,      maxx, yoffset,      paint);
-                        cavas.drawLine(0, yoffset+oneG, maxx, yoffset+oneG, paint);
-                        cavas.drawLine(0, yoffset-oneG, maxx, yoffset-oneG, paint);
-                    }
-                    canvas.drawBitmap(mBitmap, 0, 0, null);
-
-                    float[] values = mOrientationValues;
-                    if (mWidth < mHeight) {
-                        float w0 = mWidth * 0.333333f;
-                        float w  = w0 - 32;
-                        float x = w0*0.5f;
-                        for (int i=0 ; i<3 ; i++) {
-                            canvas.save(Canvas.MATRIX_SAVE_FLAG);
-                            canvas.translate(x, w*0.5f + 4.0f);
-                            canvas.save(Canvas.MATRIX_SAVE_FLAG);
-                            paint.setColor(outer);
-                            canvas.scale(w, w);
-                            canvas.drawOval(mRect, paint);
-                            canvas.restore();
-                            canvas.scale(w-5, w-5);
-                            paint.setColor(inner);
-                            canvas.rotate(-values[i]);
-                            canvas.drawPath(path, paint);
-                            canvas.restore();
-                            x += w0;
-                        }
-                    } else {
-                        float h0 = mHeight * 0.333333f;
-                        float h  = h0 - 32;
-                        float y = h0*0.5f;
-                        for (int i=0 ; i<3 ; i++) {
-                            canvas.save(Canvas.MATRIX_SAVE_FLAG);
-                            canvas.translate(mWidth - (h*0.5f + 4.0f), y);
-                            canvas.save(Canvas.MATRIX_SAVE_FLAG);
-                            paint.setColor(outer);
-                            canvas.scale(h, h);
-                            canvas.drawOval(mRect, paint);
-                            canvas.restore();
-                            canvas.scale(h-5, h-5);
-                            paint.setColor(inner);
-                            canvas.rotate(-values[i]);
-                            canvas.drawPath(path, paint);
-                            canvas.restore();
-                            y += h0;
-                        }
-                    }
-
-                }
-            }
-        }
-
-        public void onSensorChanged(SensorEvent event) {
-            //Log.d(TAG, "sensor: " + sensor + ", x: " + values[0] + ", y: " + values[1] + ", z: " + values[2]);
-            synchronized (this) {
-                if (mBitmap != null) {
-                    final Canvas canvas = mCanvas;
-                    final Paint paint = mPaint;
-                    if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
-                        for (int i=0 ; i<3 ; i++) {
-                            mOrientationValues[i] = event.values[i];
-                        }
-                    } else {
-                        float deltaX = mSpeed;
-                        float newX = mLastX + deltaX;
-
-                        int j = (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) ? 1 : 0;
-                        for (int i=0 ; i<3 ; i++) {
-                            int k = i+j*3;
-                            final float v = mYOffset + event.values[i] * mScale[j];
-                            paint.setColor(mColors[k]);
-                            canvas.drawLine(mLastX, mLastValues[k], newX, v, paint);
-                            mLastValues[k] = v;
-                        }
-                        if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
-                            mLastX += mSpeed;
-                    }
-                    invalidate();
-                }
-            }
-        }
-
-        public void onAccuracyChanged(Sensor sensor, int accuracy) {
-        }
-    }
-    
-    /**
-     * Initialization of the Activity after it is first created.  Must at least
-     * call {@link android.app.Activity#setContentView setContentView()} to
-     * describe what is to be displayed in the screen.
-     */
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        // Be sure to call the super class.
-        super.onCreate(savedInstanceState);
-
-        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
-        mGraphView = new GraphView(this);
-        setContentView(mGraphView);
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        mSensorManager.registerListener(mGraphView,
-                mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
-                SensorManager.SENSOR_DELAY_FASTEST);
-        mSensorManager.registerListener(mGraphView,
-                mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
-                SensorManager.SENSOR_DELAY_FASTEST);
-        mSensorManager.registerListener(mGraphView, 
-                mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
-                SensorManager.SENSOR_DELAY_FASTEST);
-    }
-    
-    @Override
-    protected void onStop() {
-        mSensorManager.unregisterListener(mGraphView);
-        super.onStop();
-    }
-}
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/Controls7.java b/samples/ApiDemos/src/com/example/android/apis/view/Controls7.java
new file mode 100644
index 0000000..6243d3b
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/view/Controls7.java
@@ -0,0 +1,19 @@
+/*
+ * 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.apis.view;
+
+public class Controls7 extends Controls1 {}
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/Controls8.java b/samples/ApiDemos/src/com/example/android/apis/view/Controls8.java
new file mode 100644
index 0000000..4dd4291
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/view/Controls8.java
@@ -0,0 +1,19 @@
+/*
+ * 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.apis.view;
+
+public class Controls8 extends Controls1 {}
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/Controls9.java b/samples/ApiDemos/src/com/example/android/apis/view/Controls9.java
new file mode 100644
index 0000000..8a940aa
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/view/Controls9.java
@@ -0,0 +1,19 @@
+/*
+ * 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.apis.view;
+
+public class Controls9 extends Controls1 {}
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/Gallery1.java b/samples/ApiDemos/src/com/example/android/apis/view/Gallery1.java
deleted file mode 100644
index b252d5a..0000000
--- a/samples/ApiDemos/src/com/example/android/apis/view/Gallery1.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2007 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.apis.view;
-
-import com.example.android.apis.R;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.os.Bundle;
-import android.view.ContextMenu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.Gallery;
-import android.widget.ImageView;
-import android.widget.Toast;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.AdapterView.OnItemClickListener;
-
-public class Gallery1 extends Activity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.gallery_1);
-
-        // Reference the Gallery view
-        Gallery g = (Gallery) findViewById(R.id.gallery);
-        // Set the adapter to our custom adapter (below)
-        g.setAdapter(new ImageAdapter(this));
-        
-        // Set a item click listener, and just Toast the clicked position
-        g.setOnItemClickListener(new OnItemClickListener() {
-            public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
-                Toast.makeText(Gallery1.this, "" + position, Toast.LENGTH_SHORT).show();
-            }
-        });
-        
-        // We also want to show context menu for longpressed items in the gallery
-        registerForContextMenu(g);
-    }
-
-    @Override
-    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
-        menu.add(R.string.gallery_2_text);
-    }
-    
-    @Override
-    public boolean onContextItemSelected(MenuItem item) {
-        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
-        Toast.makeText(this, "Longpress: " + info.position, Toast.LENGTH_SHORT).show();
-        return true;
-    }
-
-    public class ImageAdapter extends BaseAdapter {
-        private static final int ITEM_WIDTH = 136;
-        private static final int ITEM_HEIGHT = 88;
-
-        private final int mGalleryItemBackground;
-        private final Context mContext;
-
-        private final Integer[] mImageIds = {
-                R.drawable.gallery_photo_1,
-                R.drawable.gallery_photo_2,
-                R.drawable.gallery_photo_3,
-                R.drawable.gallery_photo_4,
-                R.drawable.gallery_photo_5,
-                R.drawable.gallery_photo_6,
-                R.drawable.gallery_photo_7,
-                R.drawable.gallery_photo_8
-        };
-
-        private final float mDensity;
-
-        public ImageAdapter(Context c) {
-            mContext = c;
-            // See res/values/attrs.xml for the <declare-styleable> that defines
-            // Gallery1.
-            TypedArray a = obtainStyledAttributes(R.styleable.Gallery1);
-            mGalleryItemBackground = a.getResourceId(
-                    R.styleable.Gallery1_android_galleryItemBackground, 0);
-            a.recycle();
-
-            mDensity = c.getResources().getDisplayMetrics().density;
-        }
-
-        public int getCount() {
-            return mImageIds.length;
-        }
-
-        public Object getItem(int position) {
-            return position;
-        }
-
-        public long getItemId(int position) {
-            return position;
-        }
-
-        public View getView(int position, View convertView, ViewGroup parent) {
-            ImageView imageView;
-            if (convertView == null) {
-                convertView = new ImageView(mContext);
-
-                imageView = (ImageView) convertView;
-                imageView.setScaleType(ImageView.ScaleType.FIT_XY);
-                imageView.setLayoutParams(new Gallery.LayoutParams(
-                        (int) (ITEM_WIDTH * mDensity + 0.5f),
-                        (int) (ITEM_HEIGHT * mDensity + 0.5f)));
-            
-                // The preferred Gallery item background
-                imageView.setBackgroundResource(mGalleryItemBackground);
-            } else {
-                imageView = (ImageView) convertView;
-            }
-
-            imageView.setImageResource(mImageIds[position]);
-
-            return imageView;
-        }
-    }
-}
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/Gallery2.java b/samples/ApiDemos/src/com/example/android/apis/view/Gallery2.java
deleted file mode 100644
index ed33451..0000000
--- a/samples/ApiDemos/src/com/example/android/apis/view/Gallery2.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2007 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.apis.view;
-
-import android.app.Activity;
-import android.database.Cursor;
-import android.provider.ContactsContract.Contacts;
-import android.os.Bundle;
-import android.widget.Gallery;
-import android.widget.SimpleCursorAdapter;
-import android.widget.SpinnerAdapter;
-
-// Need the following import to get access to the app resources, since this
-// class is in a sub-package.
-import com.example.android.apis.R;
-
-public class Gallery2 extends Activity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.gallery_2);
-
-        // Get a cursor with all people
-        Cursor c = getContentResolver().query(Contacts.CONTENT_URI,
-                CONTACT_PROJECTION, null, null, null);
-        startManagingCursor(c);
-
-        SpinnerAdapter adapter = new SimpleCursorAdapter(this,
-        // Use a template that displays a text view
-                android.R.layout.simple_gallery_item,
-                // Give the cursor to the list adatper
-                c,
-                // Map the NAME column in the people database to...
-                new String[] {Contacts.DISPLAY_NAME},
-                // The "text1" view defined in the XML template
-                new int[] { android.R.id.text1 });
-
-        Gallery g = (Gallery) findViewById(R.id.gallery);
-        g.setAdapter(adapter);
-    }
-
-    private static final String[] CONTACT_PROJECTION = new String[] {
-        Contacts._ID,
-        Contacts.DISPLAY_NAME
-    };
-}
\ No newline at end of file
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/ImageSwitcher1.java b/samples/ApiDemos/src/com/example/android/apis/view/ImageSwitcher1.java
deleted file mode 100644
index 7f17c82..0000000
--- a/samples/ApiDemos/src/com/example/android/apis/view/ImageSwitcher1.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2007 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.apis.view;
-
-import com.example.android.apis.R;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.animation.AnimationUtils;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.Gallery;
-import android.widget.Gallery.LayoutParams;
-import android.widget.ImageSwitcher;
-import android.widget.ImageView;
-import android.widget.ViewSwitcher;
-
-
-public class ImageSwitcher1 extends Activity implements
-        AdapterView.OnItemSelectedListener, ViewSwitcher.ViewFactory {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        requestWindowFeature(Window.FEATURE_NO_TITLE);
-
-        setContentView(R.layout.image_switcher_1);
-
-        mSwitcher = (ImageSwitcher) findViewById(R.id.switcher);
-        mSwitcher.setFactory(this);
-        mSwitcher.setInAnimation(AnimationUtils.loadAnimation(this,
-                android.R.anim.fade_in));
-        mSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this,
-                android.R.anim.fade_out));
-
-        Gallery g = (Gallery) findViewById(R.id.gallery);
-        g.setAdapter(new ImageAdapter(this));
-        g.setOnItemSelectedListener(this);
-    }
-
-    public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
-        mSwitcher.setImageResource(mImageIds[position]);
-    }
-
-    public void onNothingSelected(AdapterView<?> parent) {
-    }
-
-    public View makeView() {
-        ImageView i = new ImageView(this);
-        i.setBackgroundColor(0xFF000000);
-        i.setScaleType(ImageView.ScaleType.FIT_CENTER);
-        i.setLayoutParams(new ImageSwitcher.LayoutParams(LayoutParams.MATCH_PARENT,
-                LayoutParams.MATCH_PARENT));
-        return i;
-    }
-
-    private ImageSwitcher mSwitcher;
-
-    public class ImageAdapter extends BaseAdapter {
-        public ImageAdapter(Context c) {
-            mContext = c;
-        }
-
-        public int getCount() {
-            return mThumbIds.length;
-        }
-
-        public Object getItem(int position) {
-            return position;
-        }
-
-        public long getItemId(int position) {
-            return position;
-        }
-
-        public View getView(int position, View convertView, ViewGroup parent) {
-            ImageView i = new ImageView(mContext);
-
-            i.setImageResource(mThumbIds[position]);
-            i.setAdjustViewBounds(true);
-            i.setLayoutParams(new Gallery.LayoutParams(
-                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
-            i.setBackgroundResource(R.drawable.picture_frame);
-            return i;
-        }
-
-        private Context mContext;
-
-    }
-
-    private Integer[] mThumbIds = {
-            R.drawable.sample_thumb_0, R.drawable.sample_thumb_1,
-            R.drawable.sample_thumb_2, R.drawable.sample_thumb_3,
-            R.drawable.sample_thumb_4, R.drawable.sample_thumb_5,
-            R.drawable.sample_thumb_6, R.drawable.sample_thumb_7};
-
-    private Integer[] mImageIds = {
-            R.drawable.sample_0, R.drawable.sample_1, R.drawable.sample_2,
-            R.drawable.sample_3, R.drawable.sample_4, R.drawable.sample_5,
-            R.drawable.sample_6, R.drawable.sample_7};
-
-}
diff --git a/samples/AtscTvInput/Android.mk b/samples/AtscTvInput/Android.mk
new file mode 100644
index 0000000..f7c60a7
--- /dev/null
+++ b/samples/AtscTvInput/Android.mk
@@ -0,0 +1,9 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_PACKAGE_NAME := AtscTvInput
+LOCAL_MODULE_TAGS := samples
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/samples/AtscTvInput/AndroidManifest.xml b/samples/AtscTvInput/AndroidManifest.xml
new file mode 100644
index 0000000..5fe48e5
--- /dev/null
+++ b/samples/AtscTvInput/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?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.atsctvinput">
+
+    <uses-permission android:name="android.permission.READ_EPG_DATA" />
+    <uses-permission android:name="android.permission.WRITE_EPG_DATA" />
+
+    <application android:label="@string/atsc_tv_input">
+        <activity android:name="com.example.android.atsctvinput.AtscTvInputScanActivity"
+                android:screenOrientation="landscape">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+                <action android:name="android.tv.SetupActivity" />
+            </intent-filter>
+        </activity>
+        <service android:name="com.example.android.atsctvinput.AtscTvInputService"
+            android:permission="android.permission.BIND_TV_INPUT"
+            android:process=":remoteAtscTvInput">
+            <intent-filter>
+                <action android:name="android.tv.TvInputService" />
+            </intent-filter>
+        </service>
+    </application>
+</manifest>
diff --git a/samples/AtscTvInput/_index.html b/samples/AtscTvInput/_index.html
new file mode 100644
index 0000000..3e104d1
--- /dev/null
+++ b/samples/AtscTvInput/_index.html
@@ -0,0 +1,7 @@
+<p>
+A sample application that demonstrates how to implement TV input service.
+This sample uses captured ATSC streams which includes videos and channel
+and program information. On a setup request, this app registers channels and
+programs to the framework. Also, it plays the video when the framework tunes
+to the channel.
+</p>
diff --git a/samples/AtscTvInput/res/raw/freq_1_prog_1.mpg b/samples/AtscTvInput/res/raw/freq_1_prog_1.mpg
new file mode 100644
index 0000000..276bcca
--- /dev/null
+++ b/samples/AtscTvInput/res/raw/freq_1_prog_1.mpg
Binary files differ
diff --git a/samples/AtscTvInput/res/raw/freq_2_prog_1029.mpg b/samples/AtscTvInput/res/raw/freq_2_prog_1029.mpg
new file mode 100644
index 0000000..55a4a76
--- /dev/null
+++ b/samples/AtscTvInput/res/raw/freq_2_prog_1029.mpg
Binary files differ
diff --git a/samples/AtscTvInput/res/values/strings.xml b/samples/AtscTvInput/res/values/strings.xml
new file mode 100644
index 0000000..815c821
--- /dev/null
+++ b/samples/AtscTvInput/res/values/strings.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>
+    <string name="atsc_tv_input">AtscTvInput</string>
+    <string name="label">ATSC Sample Input</string>
+    <string name="channel_scan_message">Scanning channels, please wait...</string>
+</resources>
diff --git a/samples/AtscTvInput/src/com/example/android/atsctvinput/AtscTvInputScanActivity.java b/samples/AtscTvInput/src/com/example/android/atsctvinput/AtscTvInputScanActivity.java
new file mode 100644
index 0000000..e8cb6ac
--- /dev/null
+++ b/samples/AtscTvInput/src/com/example/android/atsctvinput/AtscTvInputScanActivity.java
@@ -0,0 +1,102 @@
+/*
+ * 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.atsctvinput;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.ContentValues;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.provider.TvContract;
+import android.util.Log;
+import android.util.Pair;
+
+import com.example.android.atsctvinput.SampleTsStream.TsStream;
+import com.example.android.atsctvinput.SectionParser.EITItem;
+import com.example.android.atsctvinput.SectionParser.VCTItem;
+import com.example.atsctvinput.R;
+
+import java.util.List;
+
+/**
+ * The scan/setup activity for ATSC TvInput app.
+ */
+public class AtscTvInputScanActivity extends Activity {
+    private static final String TAG = "AtscTvInputScanActivity";
+    private static final long FAKE_SCANTIME_PER_CHANNEL_MS = 1000;
+    private ProgressDialog mProgressDialog;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mProgressDialog = new ProgressDialog(this);
+        mProgressDialog.setMessage(getResources().getString(R.string.channel_scan_message));
+        mProgressDialog.setCancelable(false);
+
+        mProgressDialog.show();
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                clearChannels();
+                doAutoScan();
+                return null;
+            }
+
+            @Override
+            protected void onPostExecute(Void result) {
+                mProgressDialog.hide();
+                AtscTvInputScanActivity.this.setResult(Activity.RESULT_OK);
+                AtscTvInputScanActivity.this.finish();
+            }
+        }.execute();
+    }
+
+    private void clearChannels() {
+        String selection = TvContract.Channels.COLUMN_SERVICE_NAME + " = ?";
+        String[] selectionArgs = new String[] {
+            AtscTvInputService.class.getName()
+        };
+        getContentResolver().delete(TvContract.Channels.CONTENT_URI, selection, selectionArgs);
+    }
+
+    private void doAutoScan() {
+        for (TsStream s : SampleTsStream.SAMPLES) {
+            Pair<VCTItem, List<EITItem>> result = SampleTsStream.extractChannelInfo(this, s);
+            if (result != null) {
+                insertChannel(result.first, s);
+                try {
+                    Thread.sleep(FAKE_SCANTIME_PER_CHANNEL_MS);
+                } catch (InterruptedException e) {
+                    // Do nothing.
+                }
+            }
+        }
+    }
+
+    public void insertChannel(VCTItem channel, TsStream stream) {
+        Log.d(TAG, "Channel " + channel.getShortName() + " " + channel.getMajorChannelNumber()
+                + "-" + channel.getMinorChannelNumber() + " is detected.");
+        ContentValues values = new ContentValues();
+        values.put(TvContract.Channels.COLUMN_SERVICE_NAME, AtscTvInputService.class.getName());
+        values.put(TvContract.Channels.COLUMN_DISPLAY_NUMBER,
+                channel.getMajorChannelNumber() + "-" + channel.getMinorChannelNumber());
+        values.put(TvContract.Channels.COLUMN_DISPLAY_NAME, channel.getShortName());
+        values.put(TvContract.Channels.COLUMN_DATA, SampleTsStream.getTuneInfo(stream));
+        getContentResolver().insert(TvContract.Channels.CONTENT_URI, values);
+    }
+}
diff --git a/samples/AtscTvInput/src/com/example/android/atsctvinput/AtscTvInputService.java b/samples/AtscTvInput/src/com/example/android/atsctvinput/AtscTvInputService.java
new file mode 100644
index 0000000..faefcee
--- /dev/null
+++ b/samples/AtscTvInput/src/com/example/android/atsctvinput/AtscTvInputService.java
@@ -0,0 +1,181 @@
+/*
+ * 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.atsctvinput;
+
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.provider.TvContract;
+import android.tv.TvInputService;
+import android.util.Log;
+import android.util.Pair;
+import android.view.Surface;
+
+import com.example.android.atsctvinput.SampleTsStream.TsStream;
+import com.example.android.atsctvinput.SectionParser.EITItem;
+import com.example.android.atsctvinput.SectionParser.VCTItem;
+
+import java.util.List;
+
+/**
+ * A sample TvInputService which plays ATSC TV stream.
+ */
+public class AtscTvInputService extends TvInputService {
+    private static final String TAG = "AtscTvInputService";
+    private static final int SEC_IN_MS = 1000;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.d(TAG, "onCreate()");
+        setAvailable(true);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        Log.d(TAG, "onDestroy()");
+    }
+
+    @Override
+    public TvInputSessionImpl onCreateSession() {
+        return new MyTvInputSessionImpl();
+    }
+
+
+    public TsStream getTsStreamForChannel(Uri channelUri) {
+        String[] projection = { TvContract.Channels.COLUMN_DATA };
+        if (channelUri == null) {
+            return null;
+        }
+        Cursor cursor = this.getContentResolver().query(
+                channelUri, projection, null, null, null);
+        if (cursor == null) {
+            return null;
+        }
+        if (cursor.getCount() < 1) {
+            cursor.close();
+            return null;
+        }
+        cursor.moveToNext();
+        TsStream stream = SampleTsStream.getTsStreamFromTuneInfo(cursor.getString(0));
+        cursor.close();
+        return stream;
+    }
+
+    private class MyTvInputSessionImpl extends TvInputSessionImpl {
+        private MediaPlayer mPlayer;
+
+        protected MyTvInputSessionImpl() {
+            mPlayer = new MediaPlayer();
+        }
+
+        @Override
+        public void onRelease() {
+            if (mPlayer != null) {
+                mPlayer.release();
+                mPlayer = null;
+            }
+        }
+
+        @Override
+        public boolean onSetSurface(Surface surface) {
+            Log.d(TAG, "onSetSurface(" + surface + ")");
+            mPlayer.setSurface(surface);
+            return true;
+        }
+
+        @Override
+        public void onSetVolume(float volume) {
+            Log.d(TAG, "onSetVolume(" + volume + ")");
+            mPlayer.setVolume(volume, volume);
+        }
+
+        @Override
+        public boolean onTune(Uri channelUri) {
+            Log.d(TAG, "onTune(" + channelUri + ")");
+            mPlayer.reset();
+            TsStream stream = getTsStreamForChannel(channelUri);
+            if (stream == null) {
+                return false;
+            }
+            new ProgramUpdateTask().execute(stream, channelUri);
+            AssetFileDescriptor afd = getResources().openRawResourceFd(stream.mResourceId);
+            try {
+                mPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(),
+                        afd.getLength());
+                mPlayer.prepare();
+                afd.close();
+            } catch (Exception e) {
+                Log.e(TAG, "Failed to tune to(" + channelUri + ")");
+                mPlayer.reset();
+                return false;
+            }
+            mPlayer.start();
+            return true;
+        }
+    }
+
+    private class ProgramUpdateTask extends AsyncTask<Object, Void, Void> {
+        @Override
+        protected Void doInBackground(Object... objs) {
+            TsStream stream = (TsStream) objs[0];
+            Uri channelUri = (Uri) objs[1];
+            Pair<VCTItem, List<EITItem>> result =
+                    SampleTsStream.extractChannelInfo(AtscTvInputService.this, stream);
+            if (result == null) {
+                return null;
+            }
+            clearPrograms(channelUri);
+            // The sample streams have passed timestamps. In order to show the metadata properly in
+            // TV app, we offset the time here.
+            long timeOffsetMs = Long.MIN_VALUE;
+            long currentTimeMs = System.currentTimeMillis();
+            for (EITItem i : result.second) {
+                if (timeOffsetMs == Long.MIN_VALUE) {
+                    timeOffsetMs = currentTimeMs - i.getStartTime() * SEC_IN_MS;
+                }
+                insertProgram(channelUri, i, timeOffsetMs);
+            }
+            return null;
+        }
+
+        private void clearPrograms(Uri channelUri) {
+            String selection = TvContract.Programs.COLUMN_CHANNEL_ID + " = ?";
+            String[] selectionArgs =
+                    new String[] { Long.toString(ContentUris.parseId(channelUri)) };
+            getContentResolver().delete(TvContract.Programs.CONTENT_URI, selection, selectionArgs);
+        }
+
+        private Uri insertProgram(Uri channelUri, EITItem event, long timeOffsetMs) {
+            Log.d(TAG, "insertProgram " + event.getTitleText());
+            ContentValues values = new ContentValues();
+            values.put(TvContract.Programs.COLUMN_CHANNEL_ID, ContentUris.parseId(channelUri));
+            values.put(TvContract.Programs.COLUMN_TITLE, event.getTitleText());
+            values.put(TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS, timeOffsetMs
+                    + event.getStartTime() * SEC_IN_MS);
+            values.put(TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS, timeOffsetMs
+                    + (event.getStartTime() + event.getLengthInSecond()) * SEC_IN_MS);
+            return getContentResolver().insert(
+                    TvContract.Programs.CONTENT_URI, values);
+        }
+    }
+}
diff --git a/samples/AtscTvInput/src/com/example/android/atsctvinput/PSIPParser.java b/samples/AtscTvInput/src/com/example/android/atsctvinput/PSIPParser.java
new file mode 100644
index 0000000..cb3480c
--- /dev/null
+++ b/samples/AtscTvInput/src/com/example/android/atsctvinput/PSIPParser.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.atsctvinput;
+
+import android.util.Log;
+
+import com.example.android.atsctvinput.SectionParser.EITItem;
+import com.example.android.atsctvinput.SectionParser.MGTItem;
+import com.example.android.atsctvinput.SectionParser.OutputListener;
+import com.example.android.atsctvinput.SectionParser.VCTItem;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * ATSC Program and System Information Protocol (PSIP) parser.
+ */
+public class PSIPParser {
+    private static final String TAG = "PSIPParser";
+
+    public static final int ATSC_SI_BASE_PID = 0x1ffb;
+    private static final int TS_PACKET_START_CODE = 0x47;
+    private static final int TS_PACKET_SIZE = 188;
+
+    private Map<Integer, Stream> mStreamMap = new HashMap<Integer, Stream>();
+    private Map<Integer, VCTItem> mSourceIdToVCTItemMap = new HashMap<Integer, VCTItem>();
+    private SectionParser mSectionParser;
+    private PSIPOutputListener mListener;
+
+    private int mPartialTSPacketSize;
+    private byte[] mPartialTSPacketBuf = new byte[TS_PACKET_SIZE];
+
+    public interface PSIPOutputListener {
+        void onEITPidDetected(int pid);
+        void onEITItemParsed(VCTItem channel, List<EITItem> items);
+    }
+
+    private class Stream {
+        private static final int INVALID_CONTINUITY_COUNTER = -1;
+        private static final int NUM_CONTINUITY_COUNTER = 16;
+
+        int mContinuityCounter = INVALID_CONTINUITY_COUNTER;
+        byte[] mData = new byte[0];
+
+        public void feedData(byte[] data, int continuityCounter, boolean startIndicator) {
+            if ((mContinuityCounter + 1) % NUM_CONTINUITY_COUNTER
+                    != continuityCounter) {
+                mData = new byte[0];
+            }
+            mContinuityCounter = continuityCounter;
+            int startPos = 0;
+            if (mData.length == 0) {
+                if (startIndicator) {
+                    startPos = (data[0] & 0xff) + 1;
+                } else {
+                    // Don't know where the section starts yet. Wait until start indicator is on.
+                    return;
+                }
+            } else {
+                if (startIndicator) {
+                    startPos = 1;
+                }
+            }
+            int prevSize = mData.length;
+            mData = Arrays.copyOf(mData, mData.length + data.length - startPos);
+            System.arraycopy(data, startPos, mData, prevSize, data.length - startPos);
+            parseSectionIfAny();
+        }
+
+        private void parseSectionIfAny() {
+            while (mData.length >= 3) {
+                if ((mData[0] & 0xff) == 0xff) {
+                    // Clear stuffing bytes according to H222.0 section 2.4.4.
+                    mData = new byte[0];
+                    break;
+                }
+                int sectionLength = (((mData[1] & 0x0f) << 8) | (mData[2] & 0xff) + 3);
+                if (mData.length < sectionLength) {
+                    break;
+                }
+                Log.d(TAG, "parseSection 0x" + Integer.toHexString(mData[0] & 0xff));
+                parseSection(Arrays.copyOfRange(mData, 0, sectionLength));
+                mData = Arrays.copyOfRange(mData, sectionLength, mData.length);
+            }
+        }
+    }
+
+    private OutputListener mSectionListener = new OutputListener() {
+        @Override
+        public void onMGTParsed(List<MGTItem> items) {
+            for (MGTItem i : items) {
+                if (i.getTableType() == MGTItem.TABLE_TYPE_EIT_0
+                        && mStreamMap.get(i.getTableTypePid()) == null) {
+                    mStreamMap.put(i.getTableTypePid(), new Stream());
+                    if (mListener != null) {
+                        mListener.onEITPidDetected(i.getTableTypePid());
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void onVCTParsed(List<VCTItem> items) {
+            for (VCTItem i : items) {
+                mSourceIdToVCTItemMap.put(i.getSourceId(), i);
+            }
+        }
+
+        @Override
+        public void onEITParsed(int sourceId, List<EITItem> items) {
+            Log.d(TAG, "onEITParsed " + sourceId);
+            VCTItem channel = mSourceIdToVCTItemMap.get(sourceId);
+            if (channel != null && mListener != null) {
+                mListener.onEITItemParsed(channel, items);
+            }
+        }
+    };
+
+    public PSIPParser(PSIPOutputListener listener) {
+        mSectionParser = new SectionParser(mSectionListener);
+        mStreamMap.put(ATSC_SI_BASE_PID, new Stream());
+        mListener = listener;
+    }
+
+    private boolean feedTSPacket(byte[] tsData, int pos) {
+        if (tsData.length < pos + TS_PACKET_SIZE) {
+            Log.d(TAG, "Data should include a single TS packet.");
+            return false;
+        }
+        if (tsData[pos + 0] != TS_PACKET_START_CODE) {
+            Log.d(TAG, "Invalid ts packet.");
+            return false;
+        }
+        if ((tsData[pos + 1] & 0x80) != 0) {
+            Log.d(TAG, "Erroneous ts packet.");
+            return false;
+        }
+        // For details for the structire of TS packet, please see H.222.0 Table 2-2.
+        int pid = ((tsData[pos + 1] & 0x1f) << 8) | (tsData[pos + 2] & 0xff);
+        boolean hasAdaptation = (tsData[pos + 3] & 0x20) != 0;
+        boolean hasPayload = (tsData[pos + 3] & 0x10) != 0;
+        boolean payloadStartIndicator = (tsData[pos + 1] & 0x40) != 0;
+        int continuityCounter = tsData[pos + 3] & 0x0f;
+        Stream stream = mStreamMap.get(pid);
+        int payloadPos = pos;
+        payloadPos += hasAdaptation ? 5 + (tsData[pos + 4] & 0xff) : 4;
+        if (!hasPayload || stream == null) {
+            // We are not interested in this packet.
+            return false;
+        }
+        stream.feedData(Arrays.copyOfRange(tsData, payloadPos, pos + TS_PACKET_SIZE),
+                continuityCounter, payloadStartIndicator);
+        return true;
+    }
+
+    public void feedTSData(byte[] tsData, int pos, int length) {
+        int origPos = pos;
+        if (mPartialTSPacketSize != 0
+                && (mPartialTSPacketSize + length) > TS_PACKET_SIZE) {
+            System.arraycopy(tsData, pos, mPartialTSPacketBuf, mPartialTSPacketSize,
+                    TS_PACKET_SIZE - mPartialTSPacketSize);
+            feedTSPacket(mPartialTSPacketBuf, 0);
+            pos += TS_PACKET_SIZE - mPartialTSPacketSize;
+            mPartialTSPacketSize = 0;
+        }
+        for (;pos <= length - TS_PACKET_SIZE; pos += TS_PACKET_SIZE) {
+            feedTSPacket(tsData, pos);
+        }
+        int remaining = origPos + length - pos;
+        if (remaining > 0) {
+            System.arraycopy(tsData, pos, mPartialTSPacketBuf, mPartialTSPacketSize, remaining);
+        }
+    }
+
+    private void parseSection(byte[] data) {
+        mSectionParser.parseSection(data);
+    }
+}
diff --git a/samples/AtscTvInput/src/com/example/android/atsctvinput/SampleTsStream.java b/samples/AtscTvInput/src/com/example/android/atsctvinput/SampleTsStream.java
new file mode 100644
index 0000000..875d69d
--- /dev/null
+++ b/samples/AtscTvInput/src/com/example/android/atsctvinput/SampleTsStream.java
@@ -0,0 +1,117 @@
+/*
+ * 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.atsctvinput;
+
+import android.content.Context;
+import android.util.Log;
+import android.util.Pair;
+
+import com.example.android.atsctvinput.PSIPParser.PSIPOutputListener;
+import com.example.android.atsctvinput.SectionParser.EITItem;
+import com.example.android.atsctvinput.SectionParser.VCTItem;
+import com.example.atsctvinput.R;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+public class SampleTsStream {
+    private static final String TAG = "SampleTsStream";
+    /*
+     * Sample MPEG2 transport streams which include ATSC PSIP data.
+     * In order to play the stream with Android mediaplayer, each stream has exactly one program
+     * and video and audio tracks are transcoded to MPEG4 and AAC respectively.
+     */
+    public static final TsStream[] SAMPLES = new TsStream[] {
+        new TsStream(R.raw.freq_1_prog_1, 1, 1),
+        new TsStream(R.raw.freq_2_prog_1029, 2, 1029),
+    };
+
+    private static final int READ_BUF_SIZE = 188;
+
+    public static String getTuneInfo(TsStream stream) {
+        return Long.toString(stream.mFrequency) + "," + Integer.toString(stream.mProgramNumber);
+    }
+
+    public static TsStream getTsStreamFromTuneInfo(String tuneInfo) {
+        String values[] = tuneInfo.split(",");
+        if (values.length != 2) {
+            return null;
+        }
+        long freq = Long.parseLong(values[0]);
+        int programNumber = Integer.parseInt(values[1]);
+        for (TsStream s : SAMPLES) {
+            if (s.mFrequency == freq && s.mProgramNumber == programNumber) {
+                return s;
+            }
+        }
+        return null;
+    }
+
+    public static Pair<VCTItem, List<EITItem>> extractChannelInfo(
+            Context context, final TsStream stream) {
+        final Object[] results = new Object[2];
+        PSIPParser mPSIPParser = new PSIPParser(new PSIPOutputListener() {
+            @Override
+            public void onEITPidDetected(int pid) {
+                // Do nothing;
+            }
+
+            @Override
+            public void onEITItemParsed(VCTItem channel, List<EITItem> items) {
+                if (channel.getProgramNumber() == stream.mProgramNumber) {
+                    results[0] = channel;
+                    results[1] = items;
+                }
+            }
+        });
+        InputStream in = context.getResources().openRawResource(stream.mResourceId);
+        byte[] buf = new byte[READ_BUF_SIZE];
+        try {
+            while (results[0] == null && results[1] == null
+                    && in.read(buf, 0, READ_BUF_SIZE) == READ_BUF_SIZE) {
+                mPSIPParser.feedTSData(buf, 0, buf.length);
+            }
+        } catch (IOException e) {
+            Log.e(TAG, "Error while detecting channel from freq " + stream.mFrequency
+                    + " program number " + stream.mProgramNumber);
+        } finally {
+            try {
+                in.close();
+            } catch (IOException e) {
+                Log.e(TAG, "Error while closing input stream for " + stream.mFrequency);
+            }
+        }
+        if (results[0] != null && results[1] != null) {
+            return new Pair<VCTItem, List<EITItem>>(
+                    (VCTItem) results[0], (List<EITItem>) results[1]);
+        }
+        return null;
+    }
+
+    public static class TsStream {
+        public final int mResourceId;
+        public final long mFrequency;
+        public final int mProgramNumber;
+
+        public TsStream(int resourceId, long frequency, int programNumber) {
+            mResourceId = resourceId;
+            mFrequency = frequency;
+            mProgramNumber = programNumber;
+        }
+    }
+}
diff --git a/samples/AtscTvInput/src/com/example/android/atsctvinput/SectionParser.java b/samples/AtscTvInput/src/com/example/android/atsctvinput/SectionParser.java
new file mode 100644
index 0000000..0c5ec28
--- /dev/null
+++ b/samples/AtscTvInput/src/com/example/android/atsctvinput/SectionParser.java
@@ -0,0 +1,405 @@
+/*
+ * 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.atsctvinput;
+
+
+import android.util.Log;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * PSIP section parser which conforms to ATSC A/65.
+ */
+public class SectionParser {
+    private static final String TAG = "SectionParser";
+
+    private static final boolean DEBUG = false;
+
+    private static final byte TABLE_ID_MGT = (byte) 0xc7;
+    private static final byte TABLE_ID_TVCT = (byte) 0xc8;
+    private static final byte TABLE_ID_CVCT = (byte) 0xc9;
+    private static final byte TABLE_ID_EIT = (byte) 0xcb;
+
+    private static final byte COMPRESSION_TYPE_NO_COMPRESSION = (byte) 0x00;
+    private static final byte MODE_SELECTED_UNICODE_RANGE_1 = (byte) 0x00;  // 0x0000 - 0x00ff
+    private static final byte MODE_UTF16 = (byte) 0x3f;
+    private static final int MAX_SHORT_NAME_BYTES = 14;
+
+    /*
+     * The following CRC table is from the generated code by the following command.
+     * $ python pycrc.py --model crc-32-mpeg --algorithm table-driven --generate c
+     * To see the details of pycrc, please visit http://www.tty1.net/pycrc/index_en.html
+     */
+    private static final int [] CRC_TABLE = {
+        0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
+        0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
+        0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+        0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+        0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
+        0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+        0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
+        0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
+        0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+        0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
+        0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
+        0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+        0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
+        0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+        0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+        0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
+        0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
+        0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+        0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
+        0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
+        0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+        0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
+        0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
+        0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+        0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
+        0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
+        0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+        0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
+        0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
+        0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+        0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
+        0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
+        0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+        0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+        0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
+        0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+        0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
+        0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
+        0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+        0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
+        0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
+        0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+        0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
+        0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+        0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+        0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
+        0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
+        0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+        0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
+        0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
+        0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+        0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
+        0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
+        0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+        0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
+        0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
+        0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+        0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
+        0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
+        0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+        0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
+        0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
+        0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+        0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+    };
+
+    public interface OutputListener {
+        void onMGTParsed(List<MGTItem> items);
+        void onVCTParsed(List<VCTItem> items);
+        void onEITParsed(int sourceId, List<EITItem> items);
+    }
+
+    public static class MGTItem {
+        public static final int TABLE_TYPE_EIT_0 = 0x0100;
+        private int mTableType;
+        private int mTableTypePid;
+
+        public MGTItem(int tableType, int tableTypePid) {
+            mTableType = tableType;
+            mTableTypePid = tableTypePid;
+        }
+
+        public int getTableType() {
+            return mTableType;
+        }
+
+        public int getTableTypePid() {
+            return mTableTypePid;
+        }
+    }
+
+    public static class VCTItem {
+        private String mShortName;
+        private int mProgramNumber;
+        private int mMajorChannelNumber;
+        private int mMinorChannelNumber;
+        private int mSourceId;
+
+        public VCTItem(String shortName, int programNumber, int majorChannelNumber,
+                int minorChannelNumber, int sourceId) {
+            mShortName = shortName;
+            mProgramNumber = programNumber;
+            mMajorChannelNumber = majorChannelNumber;
+            mMinorChannelNumber = minorChannelNumber;
+            mSourceId = sourceId;
+        }
+
+        public String getShortName() {
+            return mShortName;
+        }
+
+        public int getProgramNumber() {
+            return mProgramNumber;
+        }
+
+        public int getMajorChannelNumber() {
+            return mMajorChannelNumber;
+        }
+
+        public int getMinorChannelNumber() {
+            return mMinorChannelNumber;
+        }
+
+        public int getSourceId() {
+            return mSourceId;
+        }
+    }
+
+    public static class EITItem {
+        private String mTitleText;
+        private long mStartTime;
+        private int mLengthInSecond;
+
+        public EITItem(String titleText, long startTime, int lengthInSecond) {
+            mTitleText = titleText;
+            mStartTime = startTime;
+            mLengthInSecond = lengthInSecond;
+        }
+
+        public String getTitleText() {
+            return mTitleText;
+        }
+
+        public long getStartTime() {
+            return mStartTime;
+        }
+
+        public int getLengthInSecond() {
+            return mLengthInSecond;
+        }
+    }
+
+    private OutputListener mListener;
+
+    public SectionParser(OutputListener listener) {
+        mListener = listener;
+    }
+
+    public void parseSection(byte[] data) {
+        if (!checkSanity(data)) {
+            Log.d(TAG, "Bad CRC!");
+            return;
+        }
+        switch (data[0]) {
+            case TABLE_ID_MGT:
+                parseMGT(data);
+                break;
+            case TABLE_ID_TVCT:
+            case TABLE_ID_CVCT:
+                parseVCT(data);
+                break;
+            case TABLE_ID_EIT:
+                parseEIT(data);
+                break;
+            default:
+                break;
+        }
+    }
+
+    private void parseMGT(byte[] data) {
+        // For details of the structure for MGT, please see ATSC A/65 Table 6.2.
+        if (DEBUG) {
+            Log.d(TAG, "MGT is discovered.");
+        }
+        int tablesDefined = ((data[9] & 0xff) << 8) | (data[10] & 0xff);
+        int pos = 11;
+        List<MGTItem> results = new ArrayList<MGTItem>();
+        for (int i = 0; i < tablesDefined; ++i) {
+            int tableType = ((data[pos] & 0xff) << 8) | (data[pos + 1] & 0xff);
+            int tableTypePid = ((data[pos + 2] & 0x1f) << 8) | (data[pos + 3] & 0xff);
+            int descriptorsLength = ((data[pos + 9] & 0x0f) << 8) | (data[pos + 10] & 0xff);
+            pos += 11 + descriptorsLength;
+            if (pos >= data.length) {
+                Log.d(TAG, "Broken MGT.");
+                return;
+            }
+            results.add(new MGTItem(tableType, tableTypePid));
+        }
+        if ((data[pos] & 0xf0) != 0xf0) {
+            Log.d(TAG, "Broken MGT.");
+            return;
+        }
+        if (mListener != null) {
+            mListener.onMGTParsed(results);
+        }
+    }
+
+    private void parseVCT(byte[] data) {
+        // For details of the structure for VCT, please see ATSC A/65 Table 6.4 and 6.8.
+        if (DEBUG) {
+            Log.d(TAG, "VCT is discovered.");
+        }
+        int sectionNumber = (data[6] & 0xff);
+        int lastSectionNumber = (data[7] & 0xff);
+        int numChannelsInSection = (data[9] & 0xff);
+        int pos = 10;
+        List<VCTItem> results = new ArrayList<VCTItem>();
+        for (int i = 0; i < numChannelsInSection; ++i) {
+            String shortName = "";
+            int shortNameSize = getShortNameSize(data, pos);
+            try {
+                shortName = new String(
+                        Arrays.copyOfRange(data, pos, pos + shortNameSize), "UTF-16");
+            } catch (UnsupportedEncodingException e) {
+                e.printStackTrace();
+            }
+            if ((data[pos + 14] & 0xf0) != 0xf0) {
+                Log.d(TAG, "Broken VCT.");
+                return;
+            }
+            int majorNumber = ((data[pos + 14] & 0x0f) << 6) | ((data[pos + 15] & 0xff) >> 2);
+            int minorNumber = ((data[pos + 15] & 0x03) << 8) | (data[pos + 16] & 0xff);
+            if ((majorNumber & 0x3f0) == 0x3f0) {
+                // If the six MSBs are 111111, these indicate that there is only one-part channel
+                // number. To see details, please refer A/65 Section 6.3.2.
+                majorNumber = ((majorNumber & 0xf) << 10) + minorNumber;
+                minorNumber = 0;
+            }
+            int programNumber = ((data[pos + 24] & 0xff) << 8) | (data[pos + 25] & 0xff);
+            int sourceId = ((data[pos + 28] & 0xff) << 8) | (data[pos + 29] & 0xff);
+            int descriptorsLength = ((data[pos + 30] & 0x03) << 8) | (data[pos + 31] & 0xff);
+            pos += 32 + descriptorsLength;
+            if (pos >= data.length) {
+                Log.d(TAG, "Broken VCT.");
+                return;
+            }
+            results.add(new VCTItem(shortName, programNumber, majorNumber, minorNumber, sourceId));
+        }
+        if ((data[pos] & 0xfc) != 0xfc) {
+            Log.d(TAG, "Broken VCT.");
+            return;
+        }
+        if (mListener != null) {
+            mListener.onVCTParsed(results);
+        }
+    }
+
+    private void parseEIT(byte[] data) {
+        // For details of the structure for EIT, please see ATSC A/65 Table 6.11.
+        if (DEBUG) {
+            Log.d(TAG, "EIT is discovered.");
+        }
+        int sourceId = ((data[3] & 0xff) << 8) | (data[4] & 0xff);
+        int sectionNumber = (data[6] & 0xff);
+        int lastSectionNumber = (data[7] & 0xff);
+        int numEventsInSection = (data[9] & 0xff);
+
+        int pos = 10;
+        List<EITItem> results = new ArrayList<EITItem>();
+        for (int i = 0; i < numEventsInSection; ++i) {
+            if ((data[pos] & 0xc0) != 0xc0) {
+                Log.d(TAG, "Broken EIT.");
+                return;
+            }
+            long startTime = ((data[pos + 2] & (long) 0xff) << 24) | ((data[pos + 3] & 0xff) << 16)
+                    | ((data[pos + 4] & 0xff) << 8) | (data[pos + 5] & 0xff);
+            int lengthInSecond = ((data[pos + 6] & 0x0f) << 16)
+                    | ((data[pos + 7] & 0xff) << 8) | (data[pos + 8] & 0xff);
+            int titleLength = (data[pos + 9] & 0xff);
+            String titleText = "";
+            if (titleLength > 0) {
+                titleText = extractText(data, pos + 10);
+            }
+            if ((data[pos + 10 + titleLength] & 0xf0) != 0xf0) {
+                Log.d(TAG, "Broken EIT.");
+                return;
+            }
+            int descriptorsLength = ((data[pos + 10 + titleLength] & 0x0f) << 8)
+                    | (data[pos + 10 + titleLength + 1] & 0xff);
+            pos += 10 + titleLength + 2 + descriptorsLength;
+            if (pos >= data.length) {
+                Log.d(TAG, "Broken EIT.");
+                return;
+            }
+            results.add(new EITItem(titleText, startTime, lengthInSecond));
+        }
+        if (mListener != null) {
+            mListener.onEITParsed(sourceId, results);
+        }
+    }
+
+    private int getShortNameSize(byte[] data, int offset) {
+        for (int i = 0; i < MAX_SHORT_NAME_BYTES; i += 2) {
+            if(data[offset + i] == 0 && data[offset + i + 1] == 0) {
+                return i;
+            }
+        }
+        return MAX_SHORT_NAME_BYTES;
+    }
+
+    private String extractText(byte[] data, int startOffset) {
+        int pos = startOffset;
+        int numStrings = data[pos] & 0xff;
+        pos++;
+        for (int i = 0; i < numStrings; ++i) {
+            int numSegments = data[pos + 3] & 0xff;
+            pos += 4;
+            for (int j = 0; j < numSegments; ++j) {
+                int compressionType = data[pos] & 0xff;
+                int mode = data[pos + 1] & 0xff;
+                int numBytes = data[pos + 2] & 0xff;
+                if (compressionType == COMPRESSION_TYPE_NO_COMPRESSION) {
+                    try {
+                        if (mode == MODE_UTF16) {
+                            return new String(Arrays.copyOfRange(
+                                    data, pos + 3, pos + 3 + numBytes), "UTF-16");
+                        } else if (mode == MODE_SELECTED_UNICODE_RANGE_1){
+                            return new String(Arrays.copyOfRange(
+                                    data, pos + 3, pos + 3 + numBytes), "UTF-8");
+                        }
+                    } catch (UnsupportedEncodingException e) {
+                        System.out.println("Unsupported text format.");
+                    }
+                }
+                pos += 3 + numBytes;
+            }
+        }
+        return null;
+    }
+
+    private boolean checkSanity(byte[] data) {
+        boolean hasCRC = (data[1] & 0x80) != 0; // section_syntax_indicator
+        if (hasCRC) {
+            int crc = 0xffffffff;
+            for(byte b : data) {
+                int index = ((crc >> 24) ^ (b & 0xff)) & 0xff;
+                crc = CRC_TABLE[index] ^ (crc << 8);
+            }
+            if(crc != 0){
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/samples/SampleSyncAdapter/AndroidManifest.xml b/samples/SampleSyncAdapter/AndroidManifest.xml
index 48f6fad..7402f9d 100644
--- a/samples/SampleSyncAdapter/AndroidManifest.xml
+++ b/samples/SampleSyncAdapter/AndroidManifest.xml
@@ -104,7 +104,7 @@
         </activity>
 
         <activity
-            android:name=".activites.InviteContactActivity"
+            android:name=".activities.InviteContactActivity"
             android:theme="@android:style/Theme.Dialog">
             <!--
                 We use the INVITE intent to add a raw contact to an existing contact.
@@ -133,34 +133,5 @@
             </intent-filter>
         </activity>
 
-        <activity
-            android:name=".activities.ViewStreamItemActivity"
-            android:theme="@android:style/Theme.Dialog">
-            <!--
-                We use the VIEW intent to view a stream item in our app.
-                It always comes with a lookup URI.
-            -->
-            <intent-filter>
-                <action
-                    android:name="android.intent.action.VIEW" />
-                <data
-                    android:mimeType="vnd.android.cursor.item/stream_item" />
-            </intent-filter>
-        </activity>
-
-        <activity
-            android:name=".activities.ViewStreamItemPhotoActivity"
-            android:theme="@android:style/Theme.Dialog">
-            <!--
-                We use the VIEW intent to view a stream item photo in our app.
-                It always comes with a lookup URI.
-            -->
-            <intent-filter>
-                <action
-                    android:name="android.intent.action.VIEW" />
-                <data
-                    android:mimeType="vnd.android.cursor.item/stream_item_photo" />
-            </intent-filter>
-        </activity>
     </application>
 </manifest>
diff --git a/samples/SampleSyncAdapter/res/layout/view_stream_item_activity.xml b/samples/SampleSyncAdapter/res/layout/view_stream_item_activity.xml
deleted file mode 100644
index a04d07f..0000000
--- a/samples/SampleSyncAdapter/res/layout/view_stream_item_activity.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
-/**
- * Copyright (c) 2011, 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="wrap_content"
-    android:layout_height="wrap_content">
-    <TextView
-        android:text="@string/view_stream_item_description"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content" />
-    <TextView
-        android:id="@+id/view_stream_item_uri"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content" />
-</LinearLayout>
diff --git a/samples/SampleSyncAdapter/res/layout/view_stream_item_photo_activity.xml b/samples/SampleSyncAdapter/res/layout/view_stream_item_photo_activity.xml
deleted file mode 100644
index ddc09d0..0000000
--- a/samples/SampleSyncAdapter/res/layout/view_stream_item_photo_activity.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
-/**
- * Copyright (c) 2011, 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="wrap_content"
-    android:layout_height="wrap_content">
-    <TextView
-        android:text="@string/view_stream_item_photo_description"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content" />
-    <TextView
-        android:id="@+id/view_stream_item_photo_uri"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content" />
-</LinearLayout>
diff --git a/samples/SampleSyncAdapter/res/values/strings.xml b/samples/SampleSyncAdapter/res/values/strings.xml
index 22fe14e..84c94d1 100644
--- a/samples/SampleSyncAdapter/res/values/strings.xml
+++ b/samples/SampleSyncAdapter/res/values/strings.xml
@@ -129,14 +129,4 @@
 
         This is the group uri:</string>
 
-    <!-- The description for the view stream item -->
-    <string name="view_stream_item_description">This would now show the details of the stream item.
-
-        This is the uri of the stream item:</string>
-
-    <!-- The description for the view stream item photo -->
-    <string name="view_stream_item_photo_description">This would now show the details of the stream item photo.
-
-        This is the uri of the photo:</string>
-
 </resources>
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/res/xml-v14/contacts.xml b/samples/SampleSyncAdapter/res/xml-v14/contacts.xml
index 48e079a..b4ad2a0 100644
--- a/samples/SampleSyncAdapter/res/xml-v14/contacts.xml
+++ b/samples/SampleSyncAdapter/res/xml-v14/contacts.xml
@@ -24,8 +24,6 @@
     viewContactNotifyService="com.example.android.samplesync.notifier.NotifierService"
     viewGroupActivity="com.example.android.samplesync.activities.ViewGroupActivity"
     viewGroupActionLabel="@string/view_group_action_label"
-    viewStreamItemActivity="com.example.android.samplesync.activities.ViewStreamItemActivity"
-    viewStreamItemPhotoActivity="com.example.android.samplesync.activities.ViewStreamItemPhotoActivity"
 >
 
     <ContactsDataKind
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemActivity.java
deleted file mode 100644
index 6d54f31..0000000
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemActivity.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2011 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.samplesync.activities;
-
-import com.example.android.samplesync.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.widget.TextView;
-
-/**
- * Activity to handle view a stream-item. In a real app, this would show a rich view of the
- * item.
- */
-public class ViewStreamItemActivity extends Activity {
-    private static final String TAG = "ViewStreamItemActivity";
-
-    private TextView mUriTextView;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.view_stream_item_activity);
-
-        mUriTextView = (TextView) findViewById(R.id.view_stream_item_uri);
-        mUriTextView.setText(getIntent().getDataString());
-    }
-}
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemPhotoActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemPhotoActivity.java
deleted file mode 100644
index 962bc70..0000000
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemPhotoActivity.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2011 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.samplesync.activities;
-
-import com.example.android.samplesync.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.widget.TextView;
-
-/**
- * Activity to view a stream-item-photo. In a real app, this would show a fullscreen view of the
- * photo, potentially with ways to interact with it
- */
-public class ViewStreamItemPhotoActivity extends Activity {
-    private static final String TAG = "ViewStreamItemPhotoActivity";
-
-    private TextView mUriTextView;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.view_stream_item_photo_activity);
-
-        mUriTextView = (TextView) findViewById(R.id.view_stream_item_photo_uri);
-        mUriTextView.setText(getIntent().getDataString());
-    }
-}
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java
index 5b09eb1..22f4f26 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java
@@ -24,10 +24,7 @@
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
-import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.net.Uri;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Email;
@@ -41,14 +38,8 @@
 import android.provider.ContactsContract.RawContacts;
 import android.provider.ContactsContract.Settings;
 import android.provider.ContactsContract.StatusUpdates;
-import android.provider.ContactsContract.StreamItemPhotos;
-import android.provider.ContactsContract.StreamItems;
 import android.util.Log;
 
-import java.io.ByteArrayOutputStream;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -244,43 +235,6 @@
     }
 
     /**
-     * Demonstrate how to add stream items and stream item photos to a raw
-     * contact. This just adds items for all of the contacts for this sync
-     * adapter with some locally created text and an image. You should check
-     * for stream items on the server that you are syncing with and use the
-     * text and photo data from there instead.
-     *
-     * @param context The context of Authenticator Activity
-     * @param rawContacts The list of users we want to update
-     */
-    public static void addStreamItems(Context context, List<RawContact> rawContacts,
-             String accountName, String accountType) {
-        final ContentResolver resolver = context.getContentResolver();
-        final BatchOperation batchOperation = new BatchOperation(context, resolver);
-        String text = "This is a test stream item!";
-        String message = "via SampleSyncAdapter";
-        for (RawContact rawContact : rawContacts) {
-           addContactStreamItem(context, lookupRawContact(resolver,
-                   rawContact.getServerContactId()), accountName, accountType,
-                   text, message, batchOperation );
-        }
-        List<Uri> streamItemUris = batchOperation.execute();
-
-        // Stream item photos are added after the stream items that they are
-        // associated with, using the stream item's ID as a reference.
-
-        for (Uri uri : streamItemUris){
-          // All you need is the ID of the stream item, which is the last index
-          // path segment returned by getPathSegments().
-          long streamItemId = Long.parseLong(uri.getPathSegments().get(
-                  uri.getPathSegments().size()-1));
-          addStreamItemPhoto(context, resolver, streamItemId, accountName,
-                  accountType, batchOperation);
-        }
-        batchOperation.execute();
-    }
-
-    /**
      * After we've finished up a sync operation, we want to clean up the sync-state
      * so that we're ready for the next time.  This involves clearing out the 'dirty'
      * flag on the synced contacts - but we also have to finish the DELETE operation
@@ -596,59 +550,6 @@
     }
 
     /**
-     * Adds a stream item to a raw contact. The stream item is usually obtained
-     * from the server you are syncing with, but we create it here locally as an
-     * example.
-     *
-     * @param context the Authenticator Activity context
-     * @param rawContactId the raw contact ID that the stream item is associated with
-     * @param accountName the account name of the sync adapter
-     * @param accountType the account type of the sync adapter
-     * @param text the text of the stream item
-     * @param comments the comments for the stream item, such as where the stream item came from
-     * @param batchOperation allow us to batch together multiple operations
-     */
-    private static void addContactStreamItem(Context context, long rawContactId,
-        String accountName, String accountType, String text, String comments,
-        BatchOperation batchOperation) {
-
-        final ContentValues values = new ContentValues();
-        final ContentResolver resolver = context.getContentResolver();
-        if (rawContactId > 0){
-            values.put(StreamItems.RAW_CONTACT_ID, rawContactId);
-            values.put(StreamItems.TEXT, text);
-            values.put(StreamItems.TIMESTAMP, System.currentTimeMillis());
-            values.put(StreamItems.COMMENTS, comments);
-            values.put(StreamItems.ACCOUNT_NAME, accountName);
-            values.put(StreamItems.ACCOUNT_TYPE, accountType);
-
-            batchOperation.add(ContactOperations.newInsertCpo(
-                    StreamItems.CONTENT_URI, false, true).withValues(values).build());
-        }
-    }
-
-    private static void addStreamItemPhoto(Context context, ContentResolver
-        resolver, long streamItemId, String accountName, String accountType,
-        BatchOperation batchOperation){
-
-        ByteArrayOutputStream stream = new ByteArrayOutputStream();
-        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),
-                R.raw.img1);
-        bitmap.compress(Bitmap.CompressFormat.JPEG, 30, stream);
-        byte[] photoData = stream.toByteArray();
-
-        final ContentValues values = new ContentValues();
-        values.put(StreamItemPhotos.STREAM_ITEM_ID, streamItemId);
-        values.put(StreamItemPhotos.SORT_INDEX, 1);
-        values.put(StreamItemPhotos.PHOTO, photoData);
-        values.put(StreamItems.ACCOUNT_NAME, accountName);
-        values.put(StreamItems.ACCOUNT_TYPE, accountType);
-
-        batchOperation.add(ContactOperations.newInsertCpo(
-                StreamItems.CONTENT_PHOTO_URI, false, true).withValues(values).build());
-    }
-
-    /**
      * Clear the local system 'dirty' flag for a contact.
      *
      * @param context the Authenticator Activity context
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java
index 8aa0784..7144524 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java
@@ -119,18 +119,6 @@
 
             ContactManager.updateStatusMessages(mContext, updatedContacts);
 
-            // This is a demo of how you can add stream items for contacts on
-            // the client. This probably won't apply to
-            // 2-way contact sync providers - it's more likely that one-way
-            // sync providers (IM clients, social networking apps, etc) would
-            // use this feature. This is only supported in ICS MR1 or above.
-
-            if (Build.VERSION.SDK_INT >=
-                    Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
-                ContactManager.addStreamItems(mContext, updatedContacts,
-                    account.name, account.type);
-            }
-
             // Save off the new sync marker. On our next sync, we only want to receive
             // contacts that have changed since this sync...
             setServerSyncMarker(account, newSyncState);
diff --git a/samples/SupportLeanbackDemos/AndroidManifest.xml b/samples/SupportLeanbackDemos/AndroidManifest.xml
index ee0707d..8cf8236 100644
--- a/samples/SupportLeanbackDemos/AndroidManifest.xml
+++ b/samples/SupportLeanbackDemos/AndroidManifest.xml
@@ -9,6 +9,7 @@
     <application
         android:label="@string/app_name"
         android:icon="@drawable/ic_launcher"
+        android:banner="@drawable/ic_launcher"
         android:theme="@style/Theme.Leanback">
 
         <activity android:name="MainActivity"
diff --git a/samples/SupportLeanbackDemos/res/drawable/text_bg.xml b/samples/SupportLeanbackDemos/res/drawable/text_bg.xml
index c67924c..2f5a213 100644
--- a/samples/SupportLeanbackDemos/res/drawable/text_bg.xml
+++ b/samples/SupportLeanbackDemos/res/drawable/text_bg.xml
@@ -26,4 +26,7 @@
         android:top="7dp"
         android:right="7dp"
         android:bottom="7dp" />
+    <size
+        android:height="160dp"
+        android:width="100dp" />
 </shape>
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
index 2345ed0..ce019b3 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
@@ -27,7 +27,7 @@
 public class BrowseFragment extends android.support.v17.leanback.app.BrowseFragment {
     private static final String TAG = "leanback.BrowseFragment";
 
-    private static final int NUM_ROWS = 3;
+    private static final int NUM_ROWS = 10;
     private ArrayObjectAdapter mRowsAdapter;
 
     @Override
@@ -54,7 +54,14 @@
     }
 
     private void setupRows() {
-        mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
+        ListRowPresenter lrp = new ListRowPresenter();
+        float density = getActivity().getResources().getDisplayMetrics().density;
+        float height = 160 * density + 0.5f;
+        float expandedHeight = height + 52 * density + 0.5f;
+        lrp.setRowHeight((int)height);
+        lrp.setExpandedRowHeight((int)expandedHeight);
+
+        mRowsAdapter = new ArrayObjectAdapter(lrp);
 
         for (int i = 0; i < NUM_ROWS; ++i) {
             ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
diff --git a/samples/browseable/BasicMediaDecoder/src/com.example.android.common.media/MediaCodecWrapper.java b/samples/browseable/BasicMediaDecoder/src/com.example.android.common.media/MediaCodecWrapper.java
index a511221..a483374 100644
--- a/samples/browseable/BasicMediaDecoder/src/com.example.android.common.media/MediaCodecWrapper.java
+++ b/samples/browseable/BasicMediaDecoder/src/com.example.android.common.media/MediaCodecWrapper.java
@@ -21,6 +21,7 @@
 import android.os.Looper;
 import android.view.Surface;
 
+import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.ArrayDeque;
 import java.util.Queue;
@@ -136,7 +137,7 @@
      * @return
      */
     public static MediaCodecWrapper fromVideoFormat(final MediaFormat trackFormat,
-            Surface surface) {
+            Surface surface) throws IOException {
         MediaCodecWrapper result = null;
         MediaCodec videoCodec = null;
 
diff --git a/samples/training/NsdChat/src/com/example/android/nsdchat/ChatConnection.java b/samples/training/NsdChat/src/com/example/android/nsdchat/ChatConnection.java
index 80aa9fd..534f218 100644
--- a/samples/training/NsdChat/src/com/example/android/nsdchat/ChatConnection.java
+++ b/samples/training/NsdChat/src/com/example/android/nsdchat/ChatConnection.java
@@ -52,7 +52,9 @@
 
     public void tearDown() {
         mChatServer.tearDown();
-        mChatClient.tearDown();
+        if (mChatClient != null) {
+          mChatClient.tearDown();
+        }
     }
 
     public void connectToServer(InetAddress address, int port) {
@@ -64,15 +66,15 @@
             mChatClient.sendMessage(msg);
         }
     }
-    
+
     public int getLocalPort() {
         return mPort;
     }
-    
+
     public void setLocalPort(int port) {
         mPort = port;
     }
-    
+
 
     public synchronized void updateMessages(String msg, boolean local) {
         Log.e(TAG, "Updating message: " + msg);
@@ -142,7 +144,7 @@
                     // used.  Just grab an available one  and advertise it via Nsd.
                     mServerSocket = new ServerSocket(0);
                     setLocalPort(mServerSocket.getLocalPort());
-                    
+
                     while (!Thread.currentThread().isInterrupted()) {
                         Log.d(TAG, "ServerSocket Created, awaiting connection");
                         setSocket(mServerSocket.accept());
diff --git a/samples/training/NsdChat/src/com/example/android/nsdchat/NsdChatActivity.java b/samples/training/NsdChat/src/com/example/android/nsdchat/NsdChatActivity.java
index 47ee098..5782634 100644
--- a/samples/training/NsdChat/src/com/example/android/nsdchat/NsdChatActivity.java
+++ b/samples/training/NsdChat/src/com/example/android/nsdchat/NsdChatActivity.java
@@ -43,6 +43,7 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        Log.d(TAG, "Creating chat activity");
         setContentView(R.layout.main);
         mStatusView = (TextView) findViewById(R.id.status);
 
@@ -54,11 +55,6 @@
             }
         };
 
-        mConnection = new ChatConnection(mUpdateHandler);
-
-        mNsdHelper = new NsdHelper(this);
-        mNsdHelper.initializeNsd();
-
     }
 
     public void clickAdvertise(View v) {
@@ -101,25 +97,58 @@
     }
 
     @Override
+    protected void onStart() {
+        Log.d(TAG, "Starting.");
+        mConnection = new ChatConnection(mUpdateHandler);
+
+        mNsdHelper = new NsdHelper(this);
+        mNsdHelper.initializeNsd();
+        super.onStart();
+    }
+
+
+    @Override
     protected void onPause() {
+        Log.d(TAG, "Pausing.");
         if (mNsdHelper != null) {
             mNsdHelper.stopDiscovery();
         }
         super.onPause();
     }
-    
+
     @Override
     protected void onResume() {
+        Log.d(TAG, "Resuming.");
         super.onResume();
         if (mNsdHelper != null) {
             mNsdHelper.discoverServices();
         }
     }
-    
+
+
+    // For KitKat and earlier releases, it is necessary to remove the
+    // service registration when the application is stopped.  There's
+    // no guarantee that the onDestroy() method will be called (we're
+    // killable after onStop() returns) and the NSD service won't remove
+    // the registration for us if we're killed.
+
+    // In L and later, NsdService will automatically unregister us when
+    // our connection goes away when we're killed, so this step is
+    // optional (but recommended).
+
     @Override
-    protected void onDestroy() {
+    protected void onStop() {
+        Log.d(TAG, "Being stopped.");
         mNsdHelper.tearDown();
         mConnection.tearDown();
+        mNsdHelper = null;
+        mConnection = null;
+        super.onStop();
+    }
+
+    @Override
+    protected void onDestroy() {
+        Log.d(TAG, "Being destroyed.");
         super.onDestroy();
     }
 }
diff --git a/samples/training/NsdChat/src/com/example/android/nsdchat/NsdHelper.java b/samples/training/NsdChat/src/com/example/android/nsdchat/NsdHelper.java
index 568a79b..5111318 100644
--- a/samples/training/NsdChat/src/com/example/android/nsdchat/NsdHelper.java
+++ b/samples/training/NsdChat/src/com/example/android/nsdchat/NsdHelper.java
@@ -44,8 +44,6 @@
 
     public void initializeNsd() {
         initializeResolveListener();
-        initializeDiscoveryListener();
-        initializeRegistrationListener();
 
         //mNsdManager.init(mContext.getMainLooper(), this);
 
@@ -78,22 +76,20 @@
                     mService = null;
                 }
             }
-            
+
             @Override
             public void onDiscoveryStopped(String serviceType) {
-                Log.i(TAG, "Discovery stopped: " + serviceType);        
+                Log.i(TAG, "Discovery stopped: " + serviceType);
             }
 
             @Override
             public void onStartDiscoveryFailed(String serviceType, int errorCode) {
                 Log.e(TAG, "Discovery failed: Error code:" + errorCode);
-                mNsdManager.stopServiceDiscovery(this);
             }
 
             @Override
             public void onStopDiscoveryFailed(String serviceType, int errorCode) {
                 Log.e(TAG, "Discovery failed: Error code:" + errorCode);
-                mNsdManager.stopServiceDiscovery(this);
             }
         };
     }
@@ -125,48 +121,68 @@
             @Override
             public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) {
                 mServiceName = NsdServiceInfo.getServiceName();
+                Log.d(TAG, "Service registered: " + mServiceName);
             }
-            
+
             @Override
             public void onRegistrationFailed(NsdServiceInfo arg0, int arg1) {
+                Log.d(TAG, "Service registration failed: " + arg1);
             }
 
             @Override
             public void onServiceUnregistered(NsdServiceInfo arg0) {
+                Log.d(TAG, "Service unregistered: " + arg0.getServiceName());
             }
-            
+
             @Override
             public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
+                Log.d(TAG, "Service unregistration failed: " + errorCode);
             }
-            
+
         };
     }
 
     public void registerService(int port) {
+        tearDown();  // Cancel any previous registration request
+        initializeRegistrationListener();
         NsdServiceInfo serviceInfo  = new NsdServiceInfo();
         serviceInfo.setPort(port);
         serviceInfo.setServiceName(mServiceName);
         serviceInfo.setServiceType(SERVICE_TYPE);
-        
+
         mNsdManager.registerService(
                 serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
-        
+
     }
 
     public void discoverServices() {
+        stopDiscovery();  // Cancel any existing discovery request
+        initializeDiscoveryListener();
         mNsdManager.discoverServices(
                 SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
     }
-    
+
     public void stopDiscovery() {
-        mNsdManager.stopServiceDiscovery(mDiscoveryListener);
+        if (mDiscoveryListener != null) {
+            try {
+                mNsdManager.stopServiceDiscovery(mDiscoveryListener);
+            } finally {
+            }
+            mDiscoveryListener = null;
+        }
     }
 
     public NsdServiceInfo getChosenServiceInfo() {
         return mService;
     }
-    
+
     public void tearDown() {
-        mNsdManager.unregisterService(mRegistrationListener);
+        if (mRegistrationListener != null) {
+            try {
+                mNsdManager.unregisterService(mRegistrationListener);
+            } finally {
+            }
+            mRegistrationListener = null;
+        }
     }
 }
diff --git a/scripts/symbol.py b/scripts/symbol.py
index 3789fa2..8c1fa68 100755
--- a/scripts/symbol.py
+++ b/scripts/symbol.py
@@ -93,6 +93,11 @@
     known_toolchains = [
       ("i686-android-linux-4.4.3", "x86", "i686-android-linux")
     ]
+  elif ARCH == "mips":
+    gcc_version = os.environ["TARGET_GCC_VERSION"]
+    known_toolchains = [
+      ("mipsel-linux-android-" + gcc_version, "mips", "mipsel-linux-android")
+    ]
   else:
     known_toolchains = []
 
diff --git a/sdk/build_tools_source.prop_template b/sdk/build_tools_source.prop_template
index c9bfc2f..5d62307 100644
--- a/sdk/build_tools_source.prop_template
+++ b/sdk/build_tools_source.prop_template
@@ -1,3 +1,3 @@
 Pkg.UserSrc=false
-Pkg.Revision=${PLATFORM_SDK_VERSION}.0.2
+Pkg.Revision=${PLATFORM_SDK_VERSION}.0.0
 
diff --git a/sdk/doc_source.prop_template b/sdk/doc_source.prop_template
index 523d6bd..d3cdfd5 100644
--- a/sdk/doc_source.prop_template
+++ b/sdk/doc_source.prop_template
@@ -1,4 +1,4 @@
 Pkg.UserSrc=false
-Pkg.Revision=2
+Pkg.Revision=1
 AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
 AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
diff --git a/sdk/images_armeabi-v7a_source.prop_template b/sdk/images_armeabi-v7a_source.prop_template
index 7d13fce..9c7a332 100644
--- a/sdk/images_armeabi-v7a_source.prop_template
+++ b/sdk/images_armeabi-v7a_source.prop_template
@@ -1,6 +1,6 @@
 Pkg.Desc=Android SDK Platform ${PLATFORM_VERSION}
 Pkg.UserSrc=false
-Pkg.Revision=2
+Pkg.Revision=1
 AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
 AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
 SystemImage.Abi=armeabi-v7a
diff --git a/sdk/images_armeabi_source.prop_template b/sdk/images_armeabi_source.prop_template
index ef17ea6..91e9d21 100644
--- a/sdk/images_armeabi_source.prop_template
+++ b/sdk/images_armeabi_source.prop_template
@@ -1,6 +1,6 @@
 Pkg.Desc=Android SDK Platform ${PLATFORM_VERSION}
 Pkg.UserSrc=false
-Pkg.Revision=2
+Pkg.Revision=1
 AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
 AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
 SystemImage.Abi=armeabi
diff --git a/sdk/images_x86_source.prop_template b/sdk/images_x86_source.prop_template
index 84be49d..cfbe180 100644
--- a/sdk/images_x86_source.prop_template
+++ b/sdk/images_x86_source.prop_template
@@ -1,6 +1,6 @@
 Pkg.Desc=Android SDK Platform ${PLATFORM_VERSION}
 Pkg.UserSrc=false
-Pkg.Revision=2
+Pkg.Revision=1
 AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
 AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
 SystemImage.Abi=x86
diff --git a/sdk/plat_tools_source.prop_template b/sdk/plat_tools_source.prop_template
index b83af7f..5d62307 100644
--- a/sdk/plat_tools_source.prop_template
+++ b/sdk/plat_tools_source.prop_template
@@ -1,3 +1,3 @@
 Pkg.UserSrc=false
-Pkg.Revision=${PLATFORM_SDK_VERSION}.0.1
+Pkg.Revision=${PLATFORM_SDK_VERSION}.0.0
 
diff --git a/sdk/source_source.prop_template b/sdk/source_source.prop_template
index 523d6bd..d3cdfd5 100644
--- a/sdk/source_source.prop_template
+++ b/sdk/source_source.prop_template
@@ -1,4 +1,4 @@
 Pkg.UserSrc=false
-Pkg.Revision=2
+Pkg.Revision=1
 AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
 AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
diff --git a/sdk/support_source.prop_template b/sdk/support_source.prop_template
index 20022d2..ba7e6fb 100644
--- a/sdk/support_source.prop_template
+++ b/sdk/support_source.prop_template
@@ -1,5 +1,5 @@
 Pkg.UserSrc=false
-Pkg.Revision=${PLATFORM_SDK_VERSION}.2.0
+Pkg.Revision=${PLATFORM_SDK_VERSION}
 Extra.Vendor=android
 Extra.VendorId=android
 Extra.VendorDisplay=Android
diff --git a/testrunner/adb_interface.py b/testrunner/adb_interface.py
index fa394cd..dc43a93 100755
--- a/testrunner/adb_interface.py
+++ b/testrunner/adb_interface.py
@@ -506,3 +506,34 @@
   def GetSerialNumber(self):
     """Returns the serial number of the targeted device."""
     return self.SendCommand("get-serialno").strip()
+
+  def RuntimeReset(self, disable_keyguard=False, retry_count=3, preview_only=False):
+    """
+    Resets the Android runtime (does *not* reboot the kernel).
+
+    Blocks until the reset is complete and the package manager
+    is available.
+
+    Args:
+      disable_keyguard: if True, presses the MENU key to disable
+        key guard, after reset is finished
+      retry_count: number of times to retry reset before failing
+
+    Raises:
+      WaitForResponseTimedOutError if package manager does not respond
+      AbortError if unrecoverable error occurred
+    """
+
+    logger.Log("adb shell stop")
+    logger.Log("adb shell start")
+
+    if not preview_only:
+      self.SendShellCommand("stop", retry_count=retry_count)
+      self.SendShellCommand("start", retry_count=retry_count)
+
+    self.WaitForDevicePm()
+
+    if disable_keyguard:
+      logger.Log("input keyevent 82 ## disable keyguard")
+      if not preview_only:
+        self.SendShellCommand("input keyevent 82", retry_count=retry_count)
diff --git a/testrunner/runtest.py b/testrunner/runtest.py
index a76d9c0..d367904 100755
--- a/testrunner/runtest.py
+++ b/testrunner/runtest.py
@@ -73,11 +73,12 @@
   # default value for make -jX
   _DEFAULT_JOBS = 16
 
-  _DALVIK_VERIFIER_OFF_PROP = "dalvik.vm.dexopt-flags = v=n"
+  _DALVIK_VERIFIER_PROP = "dalvik.vm.dexopt-flags"
+  _DALVIK_VERIFIER_OFF_VALUE = "v=n"
+  _DALVIK_VERIFIER_OFF_PROP = "%s = %s" %(_DALVIK_VERIFIER_PROP, _DALVIK_VERIFIER_OFF_VALUE)
 
   # regular expression to match path to artifacts to install in make output
-  _RE_MAKE_INSTALL = re.compile(r'INSTALL-PATH:\s(.+)\s(.+)')
-
+  _RE_MAKE_INSTALL = re.compile(r'INSTALL-PATH:\s([^\s]+)\s(.*)$')
 
   def __init__(self):
     # disable logging of timestamp
@@ -113,6 +114,9 @@
     parser.add_option("-n", "--skip_execute", dest="preview", default=False,
                       action="store_true",
                       help="Do not execute, just preview commands")
+    parser.add_option("-i", "--build-install-only", dest="build_install_only", default=False,
+                      action="store_true",
+                      help="Do not execute, build tests and install to device only")
     parser.add_option("-r", "--raw-mode", dest="raw_mode", default=False,
                       action="store_true",
                       help="Raw mode (for output to other tools)")
@@ -193,7 +197,6 @@
       self._adb.SetDeviceTarget()
     elif self._options.serial is not None:
       self._adb.SetTargetSerial(self._options.serial)
-
     if self._options.verbose:
       logger.SetVerbose(True)
 
@@ -247,7 +250,9 @@
 
     tests = self._GetTestsToRun()
     # turn off dalvik verifier if necessary
-    self._TurnOffVerifier(tests)
+    # TODO: skip turning off verifier for now, since it puts device in bad
+    # state b/14088982
+    #self._TurnOffVerifier(tests)
     self._DoFullBuild(tests)
 
     target_tree = make_tree.MakeTree()
@@ -267,7 +272,9 @@
         target_tree.AddPath("external/emma")
 
       target_list = target_tree.GetPrunedMakeList()
+      target_dir_list = [re.sub(r'Android[.]mk$', r'', i) for i in target_list]
       target_build_string = " ".join(target_list)
+      target_dir_build_string = " ".join(target_dir_list)
       extra_args_string = " ".join(extra_args_set)
 
       # mmm cannot be used from python, so perform a similar operation using
@@ -275,9 +282,24 @@
       cmd = 'ONE_SHOT_MAKEFILE="%s" make -j%s -C "%s" GET-INSTALL-PATH all_modules %s' % (
           target_build_string, self._options.make_jobs, self._root_path,
           extra_args_string)
+      # mmma equivalent, used when regular mmm fails
+      alt_cmd = 'make -j%s -C "%s" -f build/core/main.mk %s all_modules BUILD_MODULES_IN_PATHS="%s"' % (
+              self._options.make_jobs, self._root_path, extra_args_string, target_dir_build_string)
+
       logger.Log(cmd)
       if not self._options.preview:
-        output = run_command.RunCommand(cmd, return_output=True, timeout_time=600)
+        run_command.SetAbortOnError()
+        try:
+          output = run_command.RunCommand(cmd, return_output=True, timeout_time=600)
+          ## Chances are this failed because it didn't build the dependencies
+        except errors.AbortError:
+          logger.Log("make failed. Trying to rebuild all dependencies.")
+          logger.Log("mmma -j%s %s" %(self._options.make_jobs, target_dir_build_string))
+          # Try again with mma equivalent, which will build the dependencies
+          run_command.RunCommand(alt_cmd, return_output=False, timeout_time=600)
+          # Run mmm again to get the install paths only
+          output = run_command.RunCommand(cmd, return_output=True, timeout_time=600)
+        run_command.SetAbortOnError(False)
         logger.SilentLog(output)
         self._DoInstall(output)
 
@@ -286,19 +308,25 @@
 
     Looks for 'install:' text from make output to find artifacts to install.
 
+    Files with the .apk extension get 'adb install'ed, all other files
+    get 'adb push'ed onto the device.
+
     Args:
       make_output: stdout from make command
     """
     for line in make_output.split("\n"):
       m = self._RE_MAKE_INSTALL.match(line)
       if m:
-        install_path = m.group(2)
-        if install_path.endswith(".apk"):
-          abs_install_path = os.path.join(self._root_path, install_path)
-          logger.Log("adb install -r %s" % abs_install_path)
-          logger.Log(self._adb.Install(abs_install_path))
-        else:
-          self._PushInstallFileToDevice(install_path)
+        # strip the 'INSTALL: <name>' from the left hand side
+        # the remaining string is a space-separated list of build-generated files
+        install_paths = m.group(2)
+        for install_path in re.split(r'\s+', install_paths):
+          if install_path.endswith(".apk"):
+            abs_install_path = os.path.join(self._root_path, install_path)
+            logger.Log("adb install -r %s" % abs_install_path)
+            logger.Log(self._adb.Install(abs_install_path))
+          else:
+            self._PushInstallFileToDevice(install_path)
 
   def _PushInstallFileToDevice(self, install_path):
     m = self._re_make_install_path.match(install_path)
@@ -406,7 +434,7 @@
     turns off verifier and reboots device to allow change to take effect.
     """
     # hack to check if these are frameworks/base tests. If so, turn off verifier
-    # to allow framework tests to access package-private framework api
+    # to allow framework tests to access private/protected/package-private framework api
     framework_test = False
     for test in test_list:
       if os.path.commonprefix([test.GetBuildPath(), "frameworks/base"]):
@@ -416,35 +444,54 @@
       # necessary
       output = self._adb.SendShellCommand("cat /data/local.prop")
       if not self._DALVIK_VERIFIER_OFF_PROP in output:
+
+        # Read the existing dalvik verifier flags.
+        old_prop_value = self._adb.SendShellCommand("getprop %s" \
+            %(self._DALVIK_VERIFIER_PROP))
+        old_prop_value = old_prop_value.strip() if old_prop_value else ""
+
+        # Append our verifier flags to existing flags
+        new_prop_value = "%s %s" %(self._DALVIK_VERIFIER_OFF_VALUE, old_prop_value)
+
+        # Update property now, as /data/local.prop is not read until reboot
+        logger.Log("adb shell setprop %s '%s'" \
+            %(self._DALVIK_VERIFIER_PROP, new_prop_value))
+        if not self._options.preview:
+          self._adb.SendShellCommand("setprop %s '%s'" \
+            %(self._DALVIK_VERIFIER_PROP, new_prop_value))
+
+        # Write prop to /data/local.prop
+        # Every time device is booted, it will pick up this value
+        new_prop_assignment = "%s = %s" %(self._DALVIK_VERIFIER_PROP, new_prop_value)
         if self._options.preview:
           logger.Log("adb shell \"echo %s >> /data/local.prop\""
-                     % self._DALVIK_VERIFIER_OFF_PROP)
+                     % new_prop_assignment)
           logger.Log("adb shell chmod 644 /data/local.prop")
-          logger.Log("adb reboot")
-          logger.Log("adb wait-for-device")
         else:
           logger.Log("Turning off dalvik verifier and rebooting")
           self._adb.SendShellCommand("\"echo %s >> /data/local.prop\""
-                                     % self._DALVIK_VERIFIER_OFF_PROP)
+                                     % new_prop_assignment)
 
-          self._ChmodReboot()
+        # Reset runtime so that dalvik picks up new verifier flags from prop
+        self._ChmodRuntimeReset()
       elif not self._options.preview:
         # check the permissions on the file
         permout = self._adb.SendShellCommand("ls -l /data/local.prop")
         if not "-rw-r--r--" in permout:
           logger.Log("Fixing permissions on /data/local.prop and rebooting")
-          self._ChmodReboot()
+          self._ChmodRuntimeReset()
 
-  def _ChmodReboot(self):
-    """Perform a chmod of /data/local.prop and reboot.
+  def _ChmodRuntimeReset(self):
+    """Perform a chmod of /data/local.prop and reset the runtime.
     """
-    self._adb.SendShellCommand("chmod 644 /data/local.prop")
-    self._adb.SendCommand("reboot")
-    # wait for device to go offline
-    time.sleep(10)
-    self._adb.SendCommand("wait-for-device", timeout_time=60,
-                          retry_count=3)
-    self._adb.EnableAdbRoot()
+    logger.Log("adb shell chmod 644 /data/local.prop ## u+w,a+r")
+    if not self._options.preview:
+      self._adb.SendShellCommand("chmod 644 /data/local.prop")
+
+    self._adb.RuntimeReset(preview_only=self._options.preview)
+
+    if not self._options.preview:
+      self._adb.EnableAdbRoot()
 
 
   def RunTests(self):
@@ -459,6 +506,10 @@
       if not self._options.skip_build:
         self._DoBuild()
 
+      if self._options.build_install_only:
+        logger.Log("Skipping test execution (due to --build-install-only flag)")
+        return
+
       for test_suite in self._GetTestsToRun():
         try:
           test_suite.Run(self._options, self._adb)
diff --git a/testrunner/test_defs.xml b/testrunner/test_defs.xml
index 751a142..c231323 100644
--- a/testrunner/test_defs.xml
+++ b/testrunner/test_defs.xml
@@ -512,11 +512,17 @@
 
 <!-- Unit tests for the phone application. -->
 <test name="phone-unit"
-    build_path="packages/apps/Phone"
+    build_path="packages/services/Telephony"
     package="com.android.phone.tests"
     continuous="true"
     coverage_target="Phone" />
 
+<test name="telecomm-unit"
+    build_path="packages/services/Telecomm"
+    package="com.android.telecomm.tests"
+    continuous="true"
+    coverage_target="Phone" />
+
 <test name="quicksearchbox"
     build_path="packages/apps/QuickSearchBox"
     package="com.android.quicksearchbox.tests"
diff --git a/testrunner/test_defs/gtest.py b/testrunner/test_defs/gtest.py
index dc72f94..cceead9 100644
--- a/testrunner/test_defs/gtest.py
+++ b/testrunner/test_defs/gtest.py
@@ -73,6 +73,7 @@
       - test_*.[c|cc|cpp]
       - *_test.[c|cc|cpp]
       - *_unittest.[c|cc|cpp]
+      - *Tests.[cc|cpp]
 
     """
     if not sub_tests_path:
@@ -101,6 +102,7 @@
       - test_*.[cc|cpp]
       - *_test.[cc|cpp]
       - *_unittest.[cc|cpp]
+      - *Tests.[cc|cpp]
 
     This method is a callback for os.path.walk.
 
@@ -115,6 +117,6 @@
   def _EvaluateFile(self, test_list, file):
     (name, ext) = os.path.splitext(file)
     if ext == ".cc" or ext == ".cpp" or ext == ".c":
-      if re.search("_test$|_test_$|_unittest$|_unittest_$|^test_", name):
+      if re.search("_test$|_test_$|_unittest$|_unittest_$|^test_|Tests$", name):
         logger.SilentLog("Found native test file %s" % file)
         test_list.append(name)
diff --git a/tools/emulator/test-apps/GpsLocationTest/Android.mk b/tools/emulator/test-apps/GpsLocationTest/Android.mk
deleted file mode 100644
index 5f90f3a..0000000
--- a/tools/emulator/test-apps/GpsLocationTest/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2011 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := GpsLocationTest
-
-LOCAL_SDK_VERSION := 4
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/emulator/test-apps/GpsLocationTest/AndroidManifest.xml b/tools/emulator/test-apps/GpsLocationTest/AndroidManifest.xml
deleted file mode 100644
index 901855e..0000000
--- a/tools/emulator/test-apps/GpsLocationTest/AndroidManifest.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 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.android.emulator.gps.test"
-      android:versionCode="1"
-      android:versionName="1.0">
-    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
-    <uses-sdk android:minSdkVersion="4" />
-    <instrumentation android:targetPackage="com.android.emulator.gps.test"
-                     android:name="android.test.InstrumentationTestRunner" />
-    <application  android:label="GPS Location Test">
-        <uses-library android:name="android.test.runner" />
-    </application>
-</manifest>
\ No newline at end of file
diff --git a/tools/emulator/test-apps/ConnectivityTest/Android.mk b/tools/emulator/test-apps/SmokeTests/Android.mk
similarity index 80%
rename from tools/emulator/test-apps/ConnectivityTest/Android.mk
rename to tools/emulator/test-apps/SmokeTests/Android.mk
index ca20d57..ccd3eb4 100644
--- a/tools/emulator/test-apps/ConnectivityTest/Android.mk
+++ b/tools/emulator/test-apps/SmokeTests/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2011 The Android Open Source Project
+# 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.
@@ -15,18 +15,18 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
 LOCAL_MODULE_TAGS := optional
 
 # Only compile source java files in this apk.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_PACKAGE_NAME := ConnectivityTest
+LOCAL_PACKAGE_NAME := EmulatorSmokeTests
 
 LOCAL_SDK_VERSION := 4
 
 LOCAL_PROGUARD_ENABLED := disabled
 
-include $(BUILD_PACKAGE)
 
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
+include $(BUILD_PACKAGE)
diff --git a/tools/emulator/test-apps/ConnectivityTest/AndroidManifest.xml b/tools/emulator/test-apps/SmokeTests/AndroidManifest.xml
similarity index 70%
rename from tools/emulator/test-apps/ConnectivityTest/AndroidManifest.xml
rename to tools/emulator/test-apps/SmokeTests/AndroidManifest.xml
index 80f65cf..8843a00 100644
--- a/tools/emulator/test-apps/ConnectivityTest/AndroidManifest.xml
+++ b/tools/emulator/test-apps/SmokeTests/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!-- 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.
@@ -14,14 +14,14 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-      package="com.android.emulator.connectivity.test"
-      android:versionCode="1"
-      android:versionName="1.0">
+      package="com.android.emulator.smoketests">
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.READ_SMS" />
     <uses-sdk android:minSdkVersion="4" />
-    <instrumentation android:targetPackage="com.android.emulator.connectivity.test" android:name="android.test.InstrumentationTestRunner" />
-    <application  android:label="Connectivity Test">
-        <uses-library android:name="android.test.runner" />
+    <instrumentation android:targetPackage="com.android.emulator.smoketests"
+                     android:name="android.support.test.runner.AndroidJUnitRunner" />
+    <application  android:label="Emulator Smoke Tests">
     </application>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/tools/emulator/test-apps/ConnectivityTest/src/com/android/emulator/connectivity/test/ConnectivityTest.java b/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/connectivity/ConnectivityTest.java
similarity index 97%
rename from tools/emulator/test-apps/ConnectivityTest/src/com/android/emulator/connectivity/test/ConnectivityTest.java
rename to tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/connectivity/ConnectivityTest.java
index 9931eb8..9fe1ebe 100644
--- a/tools/emulator/test-apps/ConnectivityTest/src/com/android/emulator/connectivity/test/ConnectivityTest.java
+++ b/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/connectivity/ConnectivityTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.emulator.connectivity.test;
+package com.android.emulator.smoketests.connectivity;
 
 import java.io.IOException;
 import java.net.URL;
diff --git a/tools/emulator/test-apps/GpsLocationTest/src/com/android/emulator/gps/test/GpsLocationTest.java b/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/gps/GpsLocationTest.java
similarity index 98%
rename from tools/emulator/test-apps/GpsLocationTest/src/com/android/emulator/gps/test/GpsLocationTest.java
rename to tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/gps/GpsLocationTest.java
index 6eb3834..1e0258c 100644
--- a/tools/emulator/test-apps/GpsLocationTest/src/com/android/emulator/gps/test/GpsLocationTest.java
+++ b/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/gps/GpsLocationTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.emulator.gps.test;
+package com.android.emulator.smoketests.gps;
 
 import android.content.Context;
 import android.location.Location;
diff --git a/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/sms/SmsTest.java b/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/sms/SmsTest.java
new file mode 100644
index 0000000..2e18cc4
--- /dev/null
+++ b/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/sms/SmsTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.android.emulator.smoketests.sms;
+
+import android.content.Context;
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.os.HandlerThread;
+import android.support.test.InjectContext;
+
+import org.junit.Assert;
+import static junit.framework.Assert.assertEquals;
+
+import org.junit.Test;
+/**
+ * Sms Test
+ *
+ * Test that an SMS message has been received
+ */
+public class SmsTest {
+
+    /**
+     * Prior to running this test an sms must be sent
+     * via DDMS
+     */
+    public final static String NUMBER = "5551212";
+    public final static String BODY = "test sms";
+    private final static int SMS_POLL_TIME_MS = 10 * 1000;
+    private final static int SIXY_SECONDS_OF_LOOPS = 6;
+    @InjectContext
+    public Context mContext;
+
+    /**
+     * Verify that an SMS has been received with the correct number and body
+     */
+    @Test
+    public void testReceivedSms() throws java.lang.InterruptedException {
+        Cursor c = getSmsCursor();
+        c.moveToFirst();
+
+        String number = c.getString(c.getColumnIndexOrThrow("address"));
+        String body = c.getString(c.getColumnIndexOrThrow("body"));
+
+        c.close();
+
+        assertEquals(NUMBER, number);
+        assertEquals(BODY, body);
+    }
+
+    private Cursor getSmsCursor() throws java.lang.InterruptedException {
+        ContentResolver r = mContext.getContentResolver();
+        Uri message = Uri.parse("content://sms/");
+        Cursor c;
+
+        for(int i = 0; i < SIXY_SECONDS_OF_LOOPS; i++) {
+            c = r.query(message,null,null,null,null);
+
+            if(c.getCount() != 0) {
+                return c;
+            }
+
+            c.close();
+            Thread.sleep(SMS_POLL_TIME_MS);
+        }
+        Assert.fail("Did not find any SMS messages. Giving up");
+        // necessary for compilation
+        return null;
+    }
+
+}
diff --git a/tools/idegen/index-gen.sh b/tools/idegen/index-gen.sh
index 5b9e24b..3363308 100755
--- a/tools/idegen/index-gen.sh
+++ b/tools/idegen/index-gen.sh
@@ -38,8 +38,8 @@
     exit 1
   fi
 fi
-tmp_file=tmp.txt
-dest_file=module-index.txt
+tmp_file=${root_dir}/tmp.txt
+dest_file=${root_dir}/module-index.txt
 
 echo "Generating index file $dest_file..."
 start=$(($(date +%s%N) / 1000000))
diff --git a/tools/idegen/intellij-gen.sh b/tools/idegen/intellij-gen.sh
index d67c1f8..860bd3c 100755
--- a/tools/idegen/intellij-gen.sh
+++ b/tools/idegen/intellij-gen.sh
@@ -32,13 +32,15 @@
 set -e
 
 progname=`basename $0`
-if [ $# -ne 1 ]
+if [ $# -lt 2 ]
 then
-    echo "Usage: $progname <module_name>"
+    echo "Usage: $progname project_dir module_dir <module_dir>..."
     exit 1
 fi
-module_name=$1
-
+project_dir=${PWD}/$1
+shift
+module_dirs=$@
+echo $module_dirs
 script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
 root_dir=$PWD
 if [ ! -e $root_dir/.repo ]; then
@@ -63,8 +65,8 @@
 
 echo "Checking for $idegenjar"
 if [ -e "$idegenjar" ]; then
-  echo "Generating project files for $module_name"
-  cmd="java -cp $idegenjar com.android.idegen.IntellijProject $index_file $module_name"
+  echo "Generating project files for $module_dirs"
+  cmd="java -cp $idegenjar com.android.idegen.IntellijProject $index_file $project_dir $module_dirs"
   echo $cmd
   $cmd
 else
diff --git a/tools/idegen/src/com/android/idegen/AggregatedModule.java b/tools/idegen/src/com/android/idegen/AggregatedModule.java
deleted file mode 100644
index 1497da7..0000000
--- a/tools/idegen/src/com/android/idegen/AggregatedModule.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * 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.android.idegen;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.logging.Logger;
-
-/**
- * Module while is a composition of many other modules.
- * <p>
- * This is needed since intellij does not allow two modules to share the same content root.
- */
-public class AggregatedModule extends Module {
-
-    private static final Logger logger = Logger.getLogger(AggregatedModule.class.getName());
-
-    private String aggregatedModuleName;
-    private Set<Module> modules;
-    private HashSet<String> directDependencies = Sets.newHashSet();
-
-    public AggregatedModule(String aggregatedName, Set<Module> modules) {
-        this.aggregatedModuleName = Preconditions.checkNotNull(aggregatedName);
-        this.modules = Preconditions.checkNotNull(modules);
-    }
-
-    public void build() throws IOException {
-        // Create an iml file that contains all the srcs of modules.
-        buildDependentModules();
-        buildDirectDependencies();
-        //buildImlFile();
-    }
-
-    @Override
-    protected File getDir() {
-        // All modules should be in the same directory so just pull the first.
-        return modules.iterator().next().getDir();
-    }
-
-    @Override
-    protected boolean isAndroidModule() {
-        for (Module module : modules) {
-            if (module.isAndroidModule()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    protected List<File> getIntermediatesDirs() {
-        List<File> result = Lists.newArrayList();
-        for (Module module : modules) {
-            Iterables.addAll(result, module.getIntermediatesDirs());
-        }
-        return result;
-    }
-
-    public void buildDirectDependencies() {
-        for (Module module : modules) {
-            Set<String> deps = module.getDirectDependencies();
-            directDependencies.addAll(deps);
-        }
-    }
-
-    @Override
-    public Set<String> getDirectDependencies() {
-        return directDependencies;
-    }
-
-    @Override
-    protected ImmutableList<File> getSourceDirs() {
-        ImmutableList.Builder<File> builder = ImmutableList.builder();
-        for (Module module : modules) {
-            builder.addAll(module.getSourceDirs());
-        }
-        return builder.build();
-    }
-
-
-    @Override
-    protected ImmutableList<File> getExcludeDirs() {
-        ImmutableList.Builder<File> builder = ImmutableList.builder();
-        for (Module module : modules) {
-            builder.addAll(module.getExcludeDirs());
-        }
-        return builder.build();
-    }
-
-    @Override
-    public Set<File> getAllDependentImlFiles() {
-        Set<File> result = Sets.newHashSet();
-        for (Module module : modules) {
-            result.addAll(module.getAllDependentImlFiles());
-        }
-        return result;
-    }
-
-    @Override
-    public File getRepoRoot() {
-        return modules.iterator().next().getRepoRoot();
-    }
-
-    @Override
-    public String getName() {
-        return aggregatedModuleName;
-    }
-
-}
diff --git a/tools/idegen/src/com/android/idegen/DirectorySearch.java b/tools/idegen/src/com/android/idegen/DirectorySearch.java
index 2ff23e3..c289ac2 100644
--- a/tools/idegen/src/com/android/idegen/DirectorySearch.java
+++ b/tools/idegen/src/com/android/idegen/DirectorySearch.java
@@ -23,6 +23,7 @@
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FilenameFilter;
+import java.io.IOException;
 import java.net.URISyntaxException;
 import java.util.HashSet;
 import java.util.logging.Level;
@@ -37,7 +38,8 @@
 
     private static final Logger logger = Logger.getLogger(DirectorySearch.class.getName());
 
-    private static final HashSet<String> SOURCE_DIRS = Sets.newHashSet();
+    public static final HashSet<String> SOURCE_DIRS = Sets.newHashSet();
+
     static {
         SOURCE_DIRS.add("src");
         SOURCE_DIRS.add("java");
@@ -51,37 +53,71 @@
             + REL_TEMPLATE_DIR;
 
     /**
+     * Returns the previously initialized repo root.
+     */
+    public static File getRepoRoot() {
+        Preconditions.checkNotNull(repoRoot, "repoRoot has not been initialized yet.  Call "
+                + "findAndInitRepoRoot() first.");
+        return repoRoot;
+    }
+
+    /**
      * Find the repo root.  This is the root branch directory of a full repo checkout.
      *
      * @param file any file inside the root.
      * @return the root directory.
      */
-    public static File findRepoRoot(File file) {
+    public static void findAndInitRepoRoot(File file) {
         Preconditions.checkNotNull(file);
         if (repoRoot != null) {
-            return repoRoot;
+            return;
         }
 
         if (file.isDirectory()) {
             File[] files = file.listFiles(new FilenameFilter() {
                 @Override
                 public boolean accept(File dir, String name) {
-                   if (".repo".equals(name)) {
-                       return true;
-                   }
-                   return false;
+                    return ".repo".equals(name);
                 }
             });
             if (files.length > 0) {
                 repoRoot = file;
-                return file;
             }
         }
         File parent = file.getParentFile();
         if (parent == null) {
-            return null;
+            throw new IllegalStateException("Repo root not found from starting point " +
+                    file.getPath());
         }
-        return findRepoRoot(parent);
+        findAndInitRepoRoot(parent);
+    }
+
+    /**
+     * Searches up the parent chain to find the closes module root directory. A module root is one
+     * with an Android.mk file in it. <p> For example, the module root for directory
+     * <code>package/apps/Contacts/src</code> is <code>packages/apps/Contacts</code>
+     *
+     * @return the module root.
+     * @throws IOException when module root is not found.
+     */
+    public static File findModuleRoot(File path) throws IOException {
+        Preconditions.checkNotNull(path);
+        File dir;
+        if (path.isFile()) {
+            dir = path.getParentFile();
+        } else {
+            dir = path;
+        }
+        while (dir != null) {
+            File makeFile = new File(dir, "Android.mk");
+            if (makeFile.exists()) {
+                return dir;
+            } else {
+                dir = dir.getParentFile();
+            }
+        }
+        // At this point, there are no parents and we have not found a module. Error.
+        throw new IOException("Module root not found for path " + path.getCanonicalPath());
     }
 
     /**
@@ -105,10 +141,19 @@
         File[] children = file.listFiles();
         for (File child : children) {
             if (child.isDirectory()) {
-                if (SOURCE_DIRS.contains(child.getName())) {
-                    builder.add(child);
+                // Recurse further down the tree first to cover case of:
+                //
+                // src/java
+                //   or
+                // java/src
+                //
+                // In either of these cases, we don't want the parent.
+                ImmutableList<File> dirs = findSourceDirs(child);
+                if (dirs.isEmpty()) {
+                    if (SOURCE_DIRS.contains(child.getName())) {
+                        builder.add(child);
+                    }
                 } else {
-                    ImmutableList<File> dirs = findSourceDirs(child);
                     builder.addAll(dirs);
                 }
             }
@@ -151,20 +196,28 @@
     private static File templateDirCurrent = null;
     private static File templateDirRoot = null;
 
-    public static File findTemplateDir() throws FileNotFoundException {
+    public static File findTemplateDir() throws IOException {
         // Cache optimization.
-        if (templateDirCurrent != null && templateDirCurrent.exists()) return templateDirCurrent;
-        if (templateDirRoot != null && templateDirRoot.exists()) return templateDirRoot;
+        if (templateDirCurrent != null && templateDirCurrent.exists()) {
+            return templateDirCurrent;
+        }
+        if (templateDirRoot != null && templateDirRoot.exists()) {
+            return templateDirRoot;
+        }
 
         File currentDir = null;
         try {
-            currentDir = new File(IntellijProject.class.getProtectionDomain().getCodeSource()
-                    .getLocation().toURI().getPath()).getParentFile();
+            currentDir = new File(
+                    IntellijProject.class.getProtectionDomain().getCodeSource().getLocation()
+                            .toURI().getPath()).getParentFile();
         } catch (URISyntaxException e) {
             logger.log(Level.SEVERE, "Could not get jar location.", e);
             return null;
         }
-
+        // Support for program execution in intellij.
+        if (currentDir.getPath().endsWith("out/production")) {
+            return new File(currentDir.getParentFile().getParentFile(), REL_TEMPLATE_DIR);
+        }
         // First check relative to current run directory.
         templateDirCurrent = new File(currentDir, REL_TEMPLATE_DIR);
         if (templateDirCurrent.exists()) {
@@ -178,7 +231,7 @@
         }
         throw new FileNotFoundException(
                 "Unable to find template dir. Tried the following locations:\n" +
-                templateDirCurrent.getAbsolutePath() + "\n" +
-                templateDirRoot.getAbsolutePath());
+                        templateDirCurrent.getCanonicalPath() + "\n" +
+                        templateDirRoot.getCanonicalPath());
     }
 }
diff --git a/tools/idegen/src/com/android/idegen/FrameworkModule.java b/tools/idegen/src/com/android/idegen/FrameworkModule.java
index 8743925..47ea35a 100644
--- a/tools/idegen/src/com/android/idegen/FrameworkModule.java
+++ b/tools/idegen/src/com/android/idegen/FrameworkModule.java
@@ -16,33 +16,35 @@
 
 package com.android.idegen;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
 import java.io.File;
+import java.io.IOException;
 
 /**
  * Special module used for framework to build one off resource directory.
  */
-public class FrameworkModule extends StandardModule {
+public class FrameworkModule extends Module {
 
     // Framework needs a special constant for it's intermediates because it does not follow
     // normal conventions.
     private static final String FRAMEWORK_INTERMEDIATES = "framework-res_intermediates";
 
-    public FrameworkModule(String moduleName, String makeFile) {
-        super(IntellijProject.FRAMEWORK_MODULE, makeFile, true);
+    public FrameworkModule(File moduleDir) throws IOException {
+        super(Preconditions.checkNotNull(moduleDir), false);
     }
 
     @Override
-    protected String buildIntermediates() {
+    protected String buildIntermediates() throws IOException {
         StringBuilder sb = new StringBuilder();
-        File intermediates = new File(repoRoot,
+        File intermediates = new File(DirectorySearch.getRepoRoot(),
                 REL_OUT_APP_DIR + File.separator +  FRAMEWORK_INTERMEDIATES);
         ImmutableList<File> intermediateSrcDirs = DirectorySearch.findSourceDirs(intermediates);
         sb.append("    <content url=\"file://").append(intermediates).append("\">\n");
         for (File src : intermediateSrcDirs) {
             sb.append("      <sourceFolder url=\"file://")
-                    .append(src.getAbsolutePath()).append("\" isTestSource=\"false\" />\n");
+                    .append(src.getCanonicalPath()).append("\" isTestSource=\"false\" />\n");
         }
         sb.append("    </content>\n");
         return sb.toString();
diff --git a/tools/idegen/src/com/android/idegen/IntellijProject.java b/tools/idegen/src/com/android/idegen/IntellijProject.java
index e49a12b..e3b8d94 100644
--- a/tools/idegen/src/com/android/idegen/IntellijProject.java
+++ b/tools/idegen/src/com/android/idegen/IntellijProject.java
@@ -17,14 +17,14 @@
 package com.android.idegen;
 
 import com.google.common.base.Preconditions;
-import com.google.common.collect.Sets;
+import com.google.common.collect.Lists;
 import com.google.common.io.Files;
 
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.Charset;
+import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Set;
 import java.util.logging.Logger;
 
 /**
@@ -32,7 +32,7 @@
  */
 public class IntellijProject {
 
-    public static final String FRAMEWORK_MODULE = "framework";
+    public static final String FRAMEWORK_MODULE_DIR = "frameworks/base";
     public static final Charset CHARSET = Charset.forName("UTF-8");
 
     private static final Logger logger = Logger.getLogger(IntellijProject.class.getName());
@@ -42,147 +42,116 @@
 
     ModuleCache cache = ModuleCache.getInstance();
 
+    boolean buildFramework;
     File indexFile;
-    File repoRoot;
-    File projectIdeaDir;
-    String moduleName;
+    File projectPath;
+    ArrayList<String> moduleDirs;
 
-    public IntellijProject(String indexFile, String moduleName) {
+    public IntellijProject(String indexFile, String projectPath, ArrayList<String> moduleDirs,
+            boolean buildFramework) {
         this.indexFile = new File(Preconditions.checkNotNull(indexFile));
-        this.moduleName = Preconditions.checkNotNull(moduleName);
-    }
-
-    private void init() throws IOException {
-        repoRoot = DirectorySearch.findRepoRoot(indexFile);
-        cache.init(indexFile);
+        this.projectPath = new File(Preconditions.checkNotNull(projectPath));
+        this.moduleDirs = Preconditions.checkNotNull(moduleDirs);
+        this.buildFramework = buildFramework;
+        DirectorySearch.findAndInitRepoRoot(this.indexFile);
     }
 
     public void build() throws IOException {
-        init();
-        buildFrameWorkModule();
-
-        // First pass, find all dependencies and cache them.
-        Module module = cache.getAndCache(moduleName);
-        if (module == null) {
-            logger.info("Module '" + moduleName + "' not found." +
-                    " Module names are case senstive.");
-            return;
-        }
-        projectIdeaDir = new File(module.getDir(), ".idea");
-        projectIdeaDir.mkdir();
-        copyTemplates();
-
-        // Second phase, build aggregate modules.
-        Set<String> deps = module.getAllDependencies();
-        for (String dep : deps) {
-            cache.buildAndCacheAggregatedModule(dep);
+        cache.init(indexFile);
+        File repoRoot = DirectorySearch.getRepoRoot();
+        if (buildFramework) {
+            File frameworkDir = new File(repoRoot, FRAMEWORK_MODULE_DIR);
+            // Some unbundled apps/branches do not include the framework.
+            if (frameworkDir.exists()) {
+                buildFrameWorkModule(new File(repoRoot, FRAMEWORK_MODULE_DIR));
+            }
         }
 
-        // Third phase, replace individual modules with aggregated modules
-        Iterable<Module> modules = cache.getModules();
-        for (Module mod : modules) {
-            replaceWithAggregate(mod);
+        for (String moduleDir : moduleDirs) {
+            // First pass, find all dependencies and cache them.
+            File dir = new File(repoRoot, moduleDir);
+            if (!dir.exists()) {
+                logger.info("Directory " + moduleDir + " does not exist in " + repoRoot +
+                        ". Are you sure the directory is correct?");
+                return;
+            }
+            Module module = cache.getAndCacheByDir(dir);
+            if (module == null) {
+                logger.info("Module '" + dir.getPath() + "' not found." +
+                        " Module names are case senstive.");
+                return;
+            }
         }
 
         // Finally create iml files for dependencies
+        Iterable<Module> modules = cache.getModules();
         for (Module mod : modules) {
             mod.buildImlFile();
         }
 
-        createModulesFile(module);
-        createVcsFile(module);
-        createNameFile(moduleName);
+        createProjectFiles();
     }
 
-    private void replaceWithAggregate(Module module) {
-        replaceWithAggregate(module.getDirectDependencies(), module.getName());
-        replaceWithAggregate(module.getAllDependencies(), module.getName());
-
-    }
-
-    private void replaceWithAggregate(Set<String> deps, String moduleName) {
-        for (String dep : Sets.newHashSet(deps)) {
-            String replacement = cache.getAggregateReplacementName(dep);
-            if (replacement != null) {
-
-                deps.remove(dep);
-                // There could be dependencies on self due to aggregation.
-                // Only add if the replacement is not self.
-                if (!replacement.equals(moduleName)) {
-                    deps.add(replacement);
-                }
-            }
-        }
+    private void createProjectFiles() throws IOException {
+        File ideaDir = new File(projectPath, ".idea");
+        ideaDir.mkdirs();
+        copyTemplates(ideaDir);
+        createModulesFile(ideaDir, cache.getModules());
+        createVcsFile(ideaDir, cache.getModules());
+        createNameFile(ideaDir, projectPath.getName());
     }
 
     /**
      * Framework module needs special handling due to one off resource path:
      * frameworks/base/Android.mk
      */
-    private void buildFrameWorkModule() throws IOException {
-        String makeFile = cache.getMakeFile(FRAMEWORK_MODULE);
-        if (makeFile == null) {
-            logger.warning("Unable to find framework module: " + FRAMEWORK_MODULE +
-                    ". Skipping.");
-        } else {
-            logger.info("makefile: " + makeFile);
-            StandardModule frameworkModule = new FrameworkModule(FRAMEWORK_MODULE,
-                    makeFile);
-            frameworkModule.build();
-            cache.put(frameworkModule);
-        }
+    private void buildFrameWorkModule(File frameworkModuleDir) throws IOException {
+        FrameworkModule frameworkModule = new FrameworkModule(frameworkModuleDir);
+        frameworkModule.build();
+        cache.put(frameworkModule);
     }
 
-    private void createModulesFile(Module module) throws IOException {
-        String modulesContent = Files.toString(
-                new File(DirectorySearch.findTemplateDir(),
-                        "idea" + File.separator + MODULES_TEMPLATE_FILE_NAME),
-                CHARSET);
+    private void createModulesFile(File ideaDir, Iterable<Module> modules) throws IOException {
+        String modulesContent = Files.toString(new File(DirectorySearch.findTemplateDir(),
+                "idea" + File.separator + MODULES_TEMPLATE_FILE_NAME), CHARSET);
         StringBuilder sb = new StringBuilder();
-        File moduleIml = module.getImlFile();
-        sb.append("      <module fileurl=\"file://").append(moduleIml.getAbsolutePath())
-                .append("\" filepath=\"").append(moduleIml.getAbsolutePath()).append("\" />\n");
-        for (String name : module.getAllDependencies()) {
-            Module mod = cache.getAndCache(name);
+        for (Module mod : modules) {
             File iml = mod.getImlFile();
-            sb.append("      <module fileurl=\"file://").append(iml.getAbsolutePath())
-                    .append("\" filepath=\"").append(iml.getAbsolutePath()).append("\" />\n");
+            sb.append("      <module fileurl=\"file://").append(iml.getCanonicalPath()).append(
+                    "\" filepath=\"").append(iml.getCanonicalPath()).append("\" />\n");
         }
         modulesContent = modulesContent.replace("@MODULES@", sb.toString());
 
-        File out = new File(projectIdeaDir, "modules.xml");
-        logger.info("Creating " + out.getAbsolutePath());
+        File out = new File(ideaDir, "modules.xml");
+        logger.info("Creating " + out.getCanonicalPath());
         Files.write(modulesContent, out, CHARSET);
     }
 
-    private void createVcsFile(Module module) throws IOException {
-        String vcsTemplate = Files.toString(
-                new File(DirectorySearch.findTemplateDir(),
-                        "idea" + File.separator + VCS_TEMPLATE_FILE_NAME),
-                CHARSET);
+    private void createVcsFile(File ideaDir, Iterable<Module> modules) throws IOException {
+        String vcsTemplate = Files.toString(new File(DirectorySearch.findTemplateDir(),
+                "idea" + File.separator + VCS_TEMPLATE_FILE_NAME), CHARSET);
 
         StringBuilder sb = new StringBuilder();
-        for (String name : module.getAllDependencies()) {
-            Module mod = cache.getAndCache(name);
+        for (Module mod : modules) {
             File dir = mod.getDir();
             File gitRoot = new File(dir, ".git");
             if (gitRoot.exists()) {
-                sb.append("    <mapping directory=\"").append(dir.getAbsolutePath())
-                        .append("\" vcs=\"Git\" />\n");
+                sb.append("    <mapping directory=\"").append(dir.getCanonicalPath()).append(
+                        "\" vcs=\"Git\" />\n");
             }
         }
         vcsTemplate = vcsTemplate.replace("@VCS@", sb.toString());
-        Files.write(vcsTemplate, new File(projectIdeaDir, "vcs.xml"), CHARSET);
+        Files.write(vcsTemplate, new File(ideaDir, "vcs.xml"), CHARSET);
     }
 
-    private void createNameFile(String name) throws IOException {
-        File out = new File(projectIdeaDir, ".name");
+    private void createNameFile(File ideaDir, String name) throws IOException {
+        File out = new File(ideaDir, ".name");
         Files.write(name, out, CHARSET);
     }
 
-    private void copyTemplates() throws IOException {
+    private void copyTemplates(File ideaDir) throws IOException {
         File templateDir = DirectorySearch.findTemplateDir();
-        copyTemplates(new File(templateDir, "idea"), projectIdeaDir);
+        copyTemplates(new File(templateDir, "idea"), ideaDir);
     }
 
     private void copyTemplates(File fromDir, File toDir) throws IOException {
@@ -191,11 +160,14 @@
         for (File file : files) {
             if (file.isDirectory()) {
                 File destDir = new File(toDir, file.getName());
+                if (!destDir.exists()) {
+                    destDir.mkdirs();
+                }
                 copyTemplates(file, destDir);
             } else {
                 File toFile = new File(toDir, file.getName());
-                logger.info("copying " + file.getAbsolutePath() + " to " +
-                        toFile.getAbsolutePath());
+                logger.info("copying " + file.getCanonicalPath() + " to " +
+                        toFile.getCanonicalPath());
                 Files.copy(file, toFile);
             }
         }
@@ -204,10 +176,32 @@
     public static void main(String[] args) {
         logger.info("Args: " + Arrays.toString(args));
 
-        String indexFile = args[0];
-        String module = args[1];
+        if (args.length < 3) {
+            logger.severe("Not enough input arguments. Aborting");
+            return;
+        }
 
-        IntellijProject intellij = new IntellijProject(indexFile, module);
+        boolean buildFramework = true;
+        int argIndex = 0;
+        String arg = args[argIndex];
+        while (arg.startsWith("--")) {
+            if  (arg.equals("--no-framework")) {
+                buildFramework = false;
+            }
+            argIndex++;
+            arg = args[argIndex];
+        }
+
+        String indexFile = args[argIndex++];
+        String projectPath = args[argIndex++];
+        // Remaining args are module directories
+        ArrayList<String> moduleDirs = Lists.newArrayList();
+        for (int i = argIndex; i < args.length; i++) {
+            moduleDirs.add(args[i]);
+        }
+
+        IntellijProject intellij = new IntellijProject(indexFile, projectPath, moduleDirs,
+                buildFramework);
         try {
             intellij.build();
         } catch (IOException e) {
diff --git a/tools/idegen/src/com/android/idegen/MakeFileParser.java b/tools/idegen/src/com/android/idegen/MakeFileParser.java
index 3594d50..9a41b09 100644
--- a/tools/idegen/src/com/android/idegen/MakeFileParser.java
+++ b/tools/idegen/src/com/android/idegen/MakeFileParser.java
@@ -22,6 +22,7 @@
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import com.google.common.io.Files;
 import com.google.common.io.LineProcessor;
 
@@ -29,7 +30,9 @@
 import java.io.IOException;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.logging.Logger;
 
@@ -41,16 +44,7 @@
     private static final Logger logger = Logger.getLogger(MakeFileParser.class.getName());
     public static final String VALUE_DELIMITER = "|";
 
-    private enum State {
-        NEW, CONTINUE
-    }
-    private enum ModuleNameKey {
-        LOCAL_PACKAGE_NAME,
-        LOCAL_MODULE
-    };
-
     private File makeFile;
-    private String moduleName;
     private HashMap<String, String> values;
 
     /**
@@ -59,11 +53,9 @@
      * A make file may contain multiple modules.
      *
      * @param makeFile The make file to parse.
-     * @param moduleName The module to extract.
      */
-    public MakeFileParser(File makeFile, String moduleName) {
+    public MakeFileParser(File makeFile) {
         this.makeFile = Preconditions.checkNotNull(makeFile);
-        this.moduleName = Preconditions.checkNotNull(moduleName);
     }
 
     public Iterable<String> getValues(String key) {
@@ -71,163 +63,214 @@
         if (str == null) {
             return null;
         }
-        return Splitter.on(VALUE_DELIMITER)
-                .trimResults()
-                .omitEmptyStrings()
-                .split(str);
+        return Splitter.on(VALUE_DELIMITER).trimResults().omitEmptyStrings().split(str);
     }
 
     /**
-     * Extracts the relevant portion of the make file and converts into key value pairs.
-     * <p>
-     * Since each make file may contain multiple build targets (modules), this method will determine
-     * which part is the correct portion for the given module name.
-     *
-     * @throws IOException
+     * Extracts the relevant portion of the make file and converts into key value pairs. <p> Since
+     * each make file may contain multiple build targets (modules), this method will determine which
+     * part is the correct portion for the given module name.
      */
     public void parse() throws IOException {
         values = Maps.newHashMap();
-        logger.info("Parsing " + makeFile.getAbsolutePath() + " for module " + moduleName);
+        logger.info("Parsing " + makeFile.getCanonicalPath());
 
-        Files.readLines(makeFile, Charset.forName("UTF-8"), new LineProcessor<Object>() {
-
-            private String key;
-
-            private State state = State.NEW;
-
-            @Override
-            public boolean processLine(String line) throws IOException {
-                String trimmed = line.trim();
-                if (Strings.isNullOrEmpty(trimmed)) {
-                    state = State.NEW;
-                    return true;
-                }
-                if (trimmed.equals("include $(CLEAR_VARS)")) {
-                    // See if we are in the right module.
-                    if (moduleName.equals(getModuleName())) {
-                        return false;
-                    } else {
-                        values.clear();
-                    }
-                } else {
-                    switch (state) {
-                        case NEW:
-                            trimmed = checkContinue(trimmed);
-                            if (trimmed.contains("=")) {
-                                String[] arr;
-                                if (trimmed.contains(":")) {
-                                    arr = trimmed.split(":=");
-                                } else {
-                                    arr = trimmed.split("\\+=");
-                                }
-                                if (arr.length > 2) {
-                                    logger.info("Malformed line " + line);
-                                } else {
-                                    // Store the key in case the line continues
-                                    this.key = arr[0].trim();
-                                    if (arr.length == 2) {
-                                        // There may be multiple values on one line.
-                                        List<String> valuesArr = tokenizeValue(arr[1].trim());
-                                        for (String value : valuesArr) {
-                                            appendValue(this.key, value);
-                                        }
-
-                                    }
-                                }
-                            } else {
-                                //logger.info("Skipping line " + line);
-                            }
-                            break;
-                        case CONTINUE:
-                            // append
-                            trimmed = checkContinue(trimmed);
-                            appendValue(key, trimmed);
-                            break;
-                        default:
-
-                    }
-                }
-                return true;
-            }
-
-            private List<String> tokenizeValue(String value) {
-                // Value may contain function calls such as "$(call all-java-files-under)".
-                // Tokens are separated by spaces unless it's between parens.
-                StringBuilder token = new StringBuilder();
-                ArrayList<String> tokens = Lists.newArrayList();
-                int parenCount = 0;
-                for (int i = 0; i < value.length(); i++) {
-                    char ch = value.charAt(i);
-                    if (parenCount == 0 && ch == ' ') {
-                        // Not in a paren and delimiter encountered.
-                        // end token
-                        if (token.length() > 0) {
-                            tokens.add(token.toString());
-                            token = new StringBuilder();
-                        }
-                    } else {
-                        token.append(ch);
-                    }
-                    if (ch == '(') {
-                        parenCount++;
-                    } else if (ch == ')') {
-                        parenCount--;
-                    }
-                }
-                // end of line check
-                if (token.length() > 0) {
-                    tokens.add(token.toString());
-                }
-                return tokens;
-            }
-
-            private String getModuleName() {
-                for (ModuleNameKey key : ModuleNameKey.values()) {
-                    String name = values.get(key.name());
-                    if (name != null) {
-                        return name;
-                    }
-                }
-                return null;
-            }
-
-            @Override
-            public Object getResult() {
-                return null;
-            }
-
-            private String checkContinue(String value) {
-                // Check for continuation character
-                if (value.charAt(value.length() - 1) == '\\') {
-                    state = State.CONTINUE;
-                    return value.substring(0, value.length() - 1);
-                }
-                state = State.NEW;
-                return value;
-            }
-
-            /**
-             * Add a value to the hash map. If the key already exists, will append instead of
-             * over-writing the existing value.
-             *
-             * @param key The hashmap key
-             * @param newValue The value to append.
-             */
-            private void appendValue(String key, String newValue) {
-                String value = values.get(key);
-                if (value == null) {
-                    values.put(key, newValue);
-                } else {
-                    values.put(key, value + VALUE_DELIMITER + newValue);
-                }
-            }
-        });
+        Files.readLines(makeFile, Charset.forName("UTF-8"), new MakeFileLineProcessor());
     }
 
     @Override
     public String toString() {
-        return Objects.toStringHelper(this)
-                .add("values", values)
-                .toString();
+        return Objects.toStringHelper(this).add("values", values).toString();
+    }
+
+    private class MakeFileLineProcessor implements LineProcessor<Object> {
+
+        private StringBuilder lineBuffer;
+
+        // Keep a list of LOCAL_ variables to clear when CLEAR_VARS is encountered.
+        private HashSet<String> localVars = Sets.newHashSet();
+
+        @Override
+        public boolean processLine(String line) throws IOException {
+            String trimmed = line.trim();
+            // Skip comments.
+            if (!trimmed.isEmpty() && trimmed.charAt(0) == '#') {
+                return true;
+            }
+            appendPartialLine(trimmed);
+
+            if (!trimmed.isEmpty() && trimmed.charAt(trimmed.length() - 1) == '\\') {
+                // This is a partial line.  Do not process yet.
+                return true;
+            }
+
+            String completeLine = lineBuffer.toString().trim();
+            // Reset the line buffer.
+            lineBuffer = null;
+
+            if (Strings.isNullOrEmpty(completeLine)) {
+                return true;
+            }
+
+            processKeyValuePairs(completeLine);
+            return true;
+        }
+
+        private void processKeyValuePairs(String line) {
+            if (line.contains("=")) {
+                String[] arr;
+                if (line.contains(":")) {
+                    arr = line.split(":=");
+                } else {
+                    arr = line.split("\\+=");
+                }
+                if (arr.length > 2) {
+                    logger.info("Malformed line " + line);
+                } else {
+                    // Store the key in case the line continues
+                    String key = arr[0].trim();
+                    if (arr.length == 2) {
+                        // There may be multiple values on one line.
+                        List<String> valuesArr = tokenizeValue(arr[1]);
+                        for (String value : valuesArr) {
+                            appendValue(key, value);
+                        }
+
+                    }
+                }
+            } else {
+                //logger.info("Skipping line " + line);
+            }
+        }
+
+        private void appendPartialLine(String line) {
+            if (lineBuffer == null) {
+                lineBuffer = new StringBuilder();
+            } else {
+                lineBuffer.append(" ");
+            }
+            if (line.endsWith("\\")) {
+                lineBuffer.append(line.substring(0, line.length() - 2).trim());
+            } else {
+                lineBuffer.append(line);
+            }
+        }
+
+        private List<String> tokenizeValue(String rawValue) {
+            String value = rawValue.trim();
+            ArrayList<String> result = Lists.newArrayList();
+            if (value.isEmpty()) {
+                return result;
+            }
+
+            // Value may contain function calls such as "$(call all-java-files-under)" or refer
+            // to variables such as "$(my_var)"
+            value = findVariables(value);
+
+            String[] tokens = value.split(" ");
+            Collections.addAll(result, tokens);
+            return result;
+        }
+
+        private String findVariables(String value) {
+
+            int variableStart = value.indexOf('$');
+            // Keep going until we substituted all variables.
+            while (variableStart > -1) {
+                StringBuilder sb = new StringBuilder();
+                sb.append(value.substring(0, variableStart));
+
+                // variable found
+                int variableEnd = findClosingParen(value, variableStart);
+                if (variableEnd > variableStart) {
+                    String result = substituteVariables(value.substring(variableStart + 2, variableEnd));
+                    sb.append(result);
+                } else {
+                    throw new IllegalArgumentException(
+                            "Malformed variable reference in make file: " + value);
+                }
+                if (variableEnd + 1 < value.length()) {
+                    sb.append(value.substring(variableEnd + 1));
+                }
+                value = sb.toString();
+                variableStart = value.indexOf('$');
+            }
+            return value;
+        }
+
+        private int findClosingParen(String value, int startIndex) {
+            int openParenCount = 0;
+            for (int i = startIndex; i < value.length(); i++) {
+                char ch = value.charAt(i);
+                if (ch == ')') {
+                    openParenCount--;
+                    if (openParenCount == 0) {
+                        return i;
+                    }
+                } else if (ch == '(') {
+                    openParenCount++;
+                }
+            }
+            return -1;
+        }
+
+        /**
+         * Look for and handle $(...) variables.
+         */
+        private String substituteVariables(String rawValue) {
+            if (rawValue.isEmpty()) {
+                return rawValue;
+            }
+            String value = rawValue;
+            if (value.startsWith("call all-java-files-under")) {
+                // Ignore the call and function, keep the args.
+                value = value.substring(25).trim();
+            } else if (value.startsWith("call")) {
+                value = value.substring(4).trim();
+            }
+
+            // Check for single variable
+            if (value.indexOf(' ') == -1) {
+                // Substitute.
+                value = values.get(value);
+                if (value == null) {
+                    value = "";
+                }
+                return value;
+            } else {
+                return findVariables(value);
+            }
+        }
+
+        @Override
+        public Object getResult() {
+            return null;
+        }
+
+        /**
+         * Add a value to the hash map. If the key already exists, will append instead of
+         * over-writing the existing value.
+         *
+         * @param key The hashmap key
+         * @param newValue The value to append.
+         */
+        private void appendValue(String key, String newValue) {
+            String value = values.get(key);
+            if (value == null) {
+                values.put(key, newValue);
+            } else {
+                values.put(key, value + VALUE_DELIMITER + newValue);
+            }
+        }
+    }
+
+    public static void main(String[] args) {
+        MakeFileParser parser = new MakeFileParser(new File(args[0]));
+        try {
+            parser.parse();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        System.out.println(parser.toString());
     }
 }
diff --git a/tools/idegen/src/com/android/idegen/Module.java b/tools/idegen/src/com/android/idegen/Module.java
index deb2281..4695ca3 100644
--- a/tools/idegen/src/com/android/idegen/Module.java
+++ b/tools/idegen/src/com/android/idegen/Module.java
@@ -17,24 +17,44 @@
 package com.android.idegen;
 
 import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import com.google.common.io.Files;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.logging.Logger;
 
 /**
- * Super class for all modules.
+ * Module constructed from a make file.
+ *
+ * TODO: read the make file and understand included source dirs in addition to searching
+ * sub-directories.  Make files can include sources that are not sub-directories.  For example, the
+ * framework module includes sources from:
+ *
+ * external/libphonenumber/java/src
+ *
+ * to provide:
+ *
+ * com.android.i18n.phonenumbers.PhoneNumberUtil;
  */
-public abstract class Module {
+public class Module {
 
     private static final Logger logger = Logger.getLogger(Module.class.getName());
 
+    public static final String REL_OUT_APP_DIR = "out/target/common/obj/APPS";
+
     private static final String IML_TEMPLATE_FILE_NAME = "module-template.iml";
+    private static final String[] AUTO_DEPENDENCIES = new String[]{"framework", "libcore"};
+    private static final String[] DIRS_WITH_AUTO_DEPENDENCIES = new String[]{"packages", "vendor",
+            "frameworks/ex", "frameworks/opt", "frameworks/support"};
 
     /**
      * All possible attributes for the make file.
@@ -45,31 +65,155 @@
         LOCAL_SRC_FILES
     }
 
-    ModuleCache moduleCache = ModuleCache.getInstance();
+    private ModuleCache moduleCache = ModuleCache.getInstance();
 
     private File imlFile;
-
     private Set<String> allDependencies = Sets.newHashSet(); // direct + indirect
-
     private Set<File> allDependentImlFiles = Sets.newHashSet();
 
-    protected abstract void build() throws IOException;
+    private File makeFile;
+    private File moduleRoot;
+    private HashSet<File> sourceFiles = Sets.newHashSet();
 
-    protected abstract String getName();
+    // Module dependencies come from LOCAL_STATIC_JAVA_LIBRARIES or LOCAL_JAVA_LIBRARIES
+    Set<String> explicitModuleNameDependencies = Sets.newHashSet();
+    // Implicit module dependencies come from src files that fall outside the module root directory.
+    // For example, if packages/apps/Contacts includes src files from packages/apps/ContactsCommon,
+    // that is an implicit module dependency.  It's not a module dependency from the build
+    // perspective but it needs to be a separate module in intellij so that the src files can be
+    // shared by multiple intellij modules.
+    Set<File> implicitModulePathDependencies = Sets.newHashSet();
 
-    protected abstract File getDir();
+    String relativeIntermediatesDir;
+    MakeFileParser makeFileParser;
+    boolean parseMakeFileForSource;
 
-    protected abstract boolean isAndroidModule();
+    public Module(File moduleDir) throws IOException {
+        this(moduleDir, true);
+    }
 
-    protected abstract List<File> getIntermediatesDirs();
+    public Module(File moduleDir, boolean parseMakeFileForSource) throws IOException {
+        this.moduleRoot = Preconditions.checkNotNull(moduleDir);
+        this.makeFile = new File(moduleDir, "Android.mk");
+        this.relativeIntermediatesDir = calculateRelativePartToRepoRoot() + REL_OUT_APP_DIR +
+                File.separatorChar + getName() + "_intermediates" + File.separator + "src";
+        this.parseMakeFileForSource = parseMakeFileForSource;
 
-    public abstract Set<String> getDirectDependencies();
+        // TODO: auto-detect when framework dependency is needed instead of using coded list.
+        for (String dir : DIRS_WITH_AUTO_DEPENDENCIES) {
+            // length + 2 to account for slash
+            boolean isDir = makeFile.getCanonicalPath().startsWith(
+                    DirectorySearch.getRepoRoot() + "/" + dir);
+            if (isDir) {
+                Collections.addAll(this.explicitModuleNameDependencies, AUTO_DEPENDENCIES);
+            }
+        }
 
-    protected abstract ImmutableList<File> getSourceDirs();
+        makeFileParser = new MakeFileParser(makeFile);
+    }
 
-    protected abstract ImmutableList<File> getExcludeDirs();
+    private String calculateRelativePartToRepoRoot() throws IOException {
+        String rel = moduleRoot.getCanonicalPath().substring(
+                DirectorySearch.getRepoRoot().getCanonicalPath().length());
+        int count = 0;
+        // Count the number of slashes to determine how far back to go.
+        for (int i = 0; i < rel.length(); i++) {
+            if (rel.charAt(i) == '/') {
+                count++;
+            }
+        }
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < count; i++) {
+            sb.append("../");
+        }
+        return sb.toString();
+    }
 
-    public abstract File getRepoRoot();
+    public void build() throws IOException {
+        makeFileParser.parse();
+        buildDependencyList();
+        buildDependentModules();
+        logger.info("Done building module " + moduleRoot);
+        logger.info(toString());
+    }
+
+    public File getDir() {
+        return moduleRoot;
+    }
+
+    public String getName() {
+        return moduleRoot.getName();
+    }
+
+    private List<String> getRelativeIntermediatesDirs() throws IOException {
+        return Lists.newArrayList(relativeIntermediatesDir);
+    }
+
+    private ImmutableList<File> getSourceDirs() {
+        return ImmutableList.copyOf(sourceFiles);
+    }
+
+    private ImmutableList<File> getExcludeDirs() {
+        return DirectorySearch.findExcludeDirs(makeFile);
+    }
+
+    private boolean isAndroidModule() {
+        File manifest = new File(moduleRoot, "AndroidManifest.xml");
+        return manifest.exists();
+    }
+
+    private void findSourceFilesAndImplicitDependencies() throws IOException {
+        Iterable<String> values = makeFileParser.getValues(Key.LOCAL_SRC_FILES.name());
+        if (values != null) {
+            for (String value : values) {
+                File src = new File(moduleRoot, value);
+
+                // value may contain garbage at this point due to relaxed make file parsing.
+                // filter by existing file.
+                if (src.exists()) {
+                    // Look for directories outside the current module directory.
+                    if (value.contains("..")) {
+                        // Find the closest Android make file.
+                        File moduleRoot = DirectorySearch.findModuleRoot(src);
+                        implicitModulePathDependencies.add(moduleRoot);
+                    } else {
+                        if (parseMakeFileForSource) {
+                            // Check if source files are subdirectories of generic parent src
+                            // directories.  If so, no need to add since they are already included.
+                            boolean alreadyIncluded = false;
+                            for (String parentDir : DirectorySearch.SOURCE_DIRS) {
+                                if (value.startsWith(parentDir)) {
+                                    alreadyIncluded = true;
+                                    break;
+                                }
+                            }
+
+                            if (!alreadyIncluded) {
+                                sourceFiles.add(src);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        sourceFiles.addAll(DirectorySearch.findSourceDirs(moduleRoot));
+    }
+
+    private void buildDependencyList() throws IOException {
+        parseDirectDependencies(Key.LOCAL_STATIC_JAVA_LIBRARIES);
+        parseDirectDependencies(Key.LOCAL_JAVA_LIBRARIES);
+        findSourceFilesAndImplicitDependencies();
+    }
+
+    private void parseDirectDependencies(Key key) {
+        Iterable<String> names = makeFileParser.getValues(key.name());
+        if (names != null) {
+            for (String dependency : names) {
+                explicitModuleNameDependencies.add(dependency);
+            }
+        }
+    }
 
     public void buildImlFile() throws IOException {
         String imlTemplate = Files.toString(
@@ -82,19 +226,24 @@
         }
         imlTemplate = imlTemplate.replace("@FACETS@", facetXml);
 
-        String moduleDir = getDir().getAbsolutePath();
+        String moduleDir = getDir().getCanonicalPath();
 
         StringBuilder sourceDirectories = new StringBuilder();
         sourceDirectories.append("    <content url=\"file://$MODULE_DIR$\">\n");
         ImmutableList<File> srcDirs = getSourceDirs();
         for (File src : srcDirs) {
-            String relative = src.getAbsolutePath().substring(moduleDir.length());
+            String relative = src.getCanonicalPath().substring(moduleDir.length());
+            boolean isTestSource = false;
+            if (relative.startsWith("/test")) {
+                isTestSource = true;
+            }
             sourceDirectories.append("      <sourceFolder url=\"file://$MODULE_DIR$")
-                    .append(relative).append("\" isTestSource=\"false\" />\n");
+                    .append(relative).append("\" isTestSource=\"").append(isTestSource)
+                    .append("\" />\n");
         }
         ImmutableList<File> excludeDirs = getExcludeDirs();
         for (File src : excludeDirs) {
-            String relative = src.getAbsolutePath().substring(moduleDir.length());
+            String relative = src.getCanonicalPath().substring(moduleDir.length());
             sourceDirectories.append("      <excludeFolder url=\"file://$MODULE_DIR$")
                     .append(relative).append("\"/>\n");
         }
@@ -106,43 +255,62 @@
         imlTemplate = imlTemplate.replace("@SOURCES@", sourceDirectories.toString());
 
         StringBuilder moduleDependencies = new StringBuilder();
-        for (String dependency : getDirectDependencies()) {
+        for (String dependency : getAllDependencies()) {
+            Module module = moduleCache.getAndCacheByDir(new File(dependency));
             moduleDependencies.append("    <orderEntry type=\"module\" module-name=\"")
-                    .append(dependency).append("\" />\n");
+                    .append(module.getName()).append("\" />\n");
         }
         imlTemplate = imlTemplate.replace("@MODULE_DEPENDENCIES@", moduleDependencies.toString());
 
         imlFile = new File(moduleDir, getName() + ".iml");
-        logger.info("Creating " + imlFile.getAbsolutePath());
+        logger.info("Creating " + imlFile.getCanonicalPath());
         Files.write(imlTemplate, imlFile, IntellijProject.CHARSET);
     }
 
-    protected String buildIntermediates() {
+    protected String buildIntermediates() throws IOException {
         StringBuilder sb = new StringBuilder();
-        for (File intermediatesDir : getIntermediatesDirs()) {
-            sb.append("    <content url=\"file://").append(intermediatesDir).append("\">\n");
-            sb.append("      <sourceFolder url=\"file://")
-                    .append(intermediatesDir.getAbsolutePath())
+        for (String intermediatesDir : getRelativeIntermediatesDirs()) {
+            sb.append("    <content url=\"file://$MODULE_DIR$/").append(intermediatesDir)
+                    .append("\">\n");
+            sb.append("      <sourceFolder url=\"file://$MODULE_DIR$/")
+                    .append(intermediatesDir)
                     .append("\" isTestSource=\"false\" />\n");
             sb.append("    </content>\n");
         }
         return sb.toString();
     }
 
-    protected void buildDependentModules() throws IOException {
-        Set<String> directDependencies = getDirectDependencies();
-        String[] copy = directDependencies.toArray(new String[directDependencies.size()]);
-        for (String dependency : copy) {
+    private void buildDependentModules() throws IOException {
+        Set<String> moduleNameDependencies = explicitModuleNameDependencies;
 
-            Module child = moduleCache.getAndCache(dependency);
+        String[] copy = moduleNameDependencies.toArray(new String[moduleNameDependencies.size()]);
+        for (String dependency : copy) {
+            logger.info("Building dependency " + dependency);
+            Module child = moduleCache.getAndCacheByName(dependency);
             if (child == null) {
-                directDependencies.remove(dependency);
+                moduleNameDependencies.remove(dependency);
             } else {
-                addAllDependencies(dependency);
-                addAllDependencies(child.getAllDependencies());
+                allDependencies.add(child.getDir().getCanonicalPath());
+                //allDependencies.addAll(child.getAllDependencies());
                 //logger.info("Adding iml " + child.getName() + " " + child.getImlFile());
                 allDependentImlFiles.add(child.getImlFile());
-                allDependentImlFiles.addAll(child.getAllDependentImlFiles());
+                //allDependentImlFiles.addAll(child.getAllDependentImlFiles());
+            }
+        }
+        // Don't include self.  The current module may have been brought in by framework
+        // dependencies which will create a circular reference.
+        allDependencies.remove(this.getDir().getCanonicalPath());
+        allDependentImlFiles.remove(this.getImlFile());
+
+        // TODO: add implicit dependencies.  Convert all modules to be based on directory.
+        for (File dependency : implicitModulePathDependencies) {
+            Module child = moduleCache.getAndCacheByDir(dependency);
+            if (child != null) {
+                allDependencies.add(child.getDir().getCanonicalPath());
+                //allDependencies.addAll(child.getAllDependencies());
+                //logger.info("Adding iml " + child.getName() + " " + child.getImlFile());
+                allDependentImlFiles.add(child.getImlFile());
+                //allDependentImlFiles.addAll(child.getAllDependentImlFiles());
             }
         }
     }
@@ -155,29 +323,22 @@
         return allDependencies;
     }
 
-    public void addAllDependencies(String dependency) {
-        this.allDependencies.add(dependency);
-    }
-
-    public void addAllDependencies(Set<String> dependencies) {
-        this.allDependencies.addAll(dependencies);
-    }
-
     public Set<File> getAllDependentImlFiles() {
         return allDependentImlFiles;
     }
 
-    private String buildAndroidFacet() {
+    private String buildAndroidFacet() throws IOException {
         // Not sure how to handle android facet for multi-module since there could be more than
         // one intermediates directory.
-        String dir = getIntermediatesDirs().get(0).getAbsolutePath();
+        String dir = getRelativeIntermediatesDirs().get(0);
         String xml = ""
                 + "  <component name=\"FacetManager\">\n"
                 + "    <facet type=\"android\" name=\"Android\">\n"
                 + "      <configuration>\n"
-                + "        <option name=\"GEN_FOLDER_RELATIVE_PATH_APT\" value=\"" + dir + "\" />\n"
-                + "        <option name=\"GEN_FOLDER_RELATIVE_PATH_AIDL\" value=\"" + dir
-                + "\" />\n"
+                + "        <option name=\"GEN_FOLDER_RELATIVE_PATH_APT\" value=\"" +
+                dir + "\" />\n"
+                + "        <option name=\"GEN_FOLDER_RELATIVE_PATH_AIDL\" value=\"" +
+                dir + "\" />\n"
                 + "        <option name=\"MANIFEST_FILE_RELATIVE_PATH\" value=\""
                 + "/AndroidManifest.xml\" />\n"
                 + "        <option name=\"RES_FOLDER_RELATIVE_PATH\" value=\"/res\" />\n"
@@ -200,12 +361,33 @@
     }
 
     @Override
+    public int hashCode() {
+        return Objects.hashCode(getName());
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        Module other = (Module) obj;
+        return Objects.equal(getName(), other.getName());
+    }
+
+    @Override
     public String toString() {
-        return Objects.toStringHelper(Module.class)
+        return Objects.toStringHelper(this)
                 .add("name", getName())
                 .add("allDependencies", allDependencies)
-                .add("iml files", allDependentImlFiles)
-                .add("imlFile", imlFile)
+                .add("iml files", allDependentImlFiles).add("imlFile", imlFile)
+                .add("makeFileParser", makeFileParser)
+                .add("explicitModuleNameDependencies", Iterables.toString(
+                        explicitModuleNameDependencies))
+                .add("implicitModulePathDependencies", Iterables.toString(
+                        implicitModulePathDependencies))
                 .toString();
     }
 }
diff --git a/tools/idegen/src/com/android/idegen/ModuleCache.java b/tools/idegen/src/com/android/idegen/ModuleCache.java
index 093242a..eb12283 100644
--- a/tools/idegen/src/com/android/idegen/ModuleCache.java
+++ b/tools/idegen/src/com/android/idegen/ModuleCache.java
@@ -18,12 +18,10 @@
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
 
 import java.io.File;
 import java.io.IOException;
 import java.util.HashMap;
-import java.util.Set;
 import java.util.logging.Logger;
 
 /**
@@ -37,7 +35,9 @@
 
     ModuleIndexes indexes;
 
-    HashMap<String, Module> modulesByName = Maps.newHashMap();
+    // Mapping of canonical module directory to module.  Use string instead of File since File
+    // does not provide equality based on canonical path.
+    HashMap<String, Module> modulesByPath = Maps.newHashMap();
 
     private ModuleCache() {
     }
@@ -51,57 +51,48 @@
         indexes.build();
     }
 
-    public Module getAndCache(String moduleName) throws IOException {
-        Preconditions.checkState(indexes != null, "You must call init() first.");
+    public Module getAndCacheByDir(File moduleDir) throws IOException {
+        Preconditions.checkNotNull(moduleDir);
 
-        Module module = modulesByName.get(moduleName);
-        if (module == null) {
-            String makeFile = indexes.getMakeFile(moduleName);
-            if (makeFile == null) {
-                logger.warning("Unable to find make file for module: " + moduleName);
-            } else {
-                module = new StandardModule(moduleName, makeFile);
+        if (moduleDir.exists()) {
+            Module module = getModule(moduleDir);
+            if (module == null) {
+                module = new Module(moduleDir);
+                // Must put module before building it.  Otherwise infinite loop.
+                putModule(moduleDir, module);
                 module.build();
-                modulesByName.put(moduleName, module);
             }
+            return module;
         }
-        return module;
+        return null;
     }
 
-    public void buildAndCacheAggregatedModule(String moduleName) throws IOException {
-        if (indexes.isPartOfAggregatedModule(moduleName)) {
-            Set<String> moduleNames = indexes.getAggregatedModules(moduleName);
-            Set<Module> modules = Sets.newHashSet();
-            for (String name : moduleNames) {
-                Module m = modulesByName.get(name);
-                if (m != null) {
-                    modules.add(m);
-                }
-            }
-            String aggregatedName = indexes.getAggregateName(moduleName);
-            AggregatedModule module = new AggregatedModule(aggregatedName, modules);
-            module.build();
-            modulesByName.put(aggregatedName, module);
+    public Module getAndCacheByName(String moduleName) throws IOException {
+        Preconditions.checkState(indexes != null, "You must call init() first.");
+        Preconditions.checkNotNull(moduleName);
+
+        String makeFile = indexes.getMakeFile(moduleName);
+        if (makeFile == null) {
+            logger.warning("Unable to find make file for module: " + moduleName);
+            return null;
         }
+        return getAndCacheByDir(new File(makeFile).getParentFile());
+    }
+
+    private void putModule(File moduleDir, Module module) throws IOException {
+        modulesByPath.put(moduleDir.getCanonicalPath(), module);
+    }
+
+    private Module getModule(File moduleDir) throws IOException {
+        return modulesByPath.get(moduleDir.getCanonicalPath());
     }
 
     public Iterable<Module> getModules() {
-        return modulesByName.values();
+        return modulesByPath.values();
     }
 
-    public String getMakeFile(String moduleName) {
-        return indexes.getMakeFile(moduleName);
-    }
-
-    public void put(StandardModule module) {
+    public void put(Module module) throws IOException {
         Preconditions.checkNotNull(module);
-        modulesByName.put(module.getName(), module);
-    }
-
-    public String getAggregateReplacementName(String moduleName) {
-        if (indexes.isPartOfAggregatedModule(moduleName)) {
-            return indexes.getAggregateName(moduleName);
-        }
-        return null;
+        putModule(module.getDir(), module);
     }
 }
diff --git a/tools/idegen/src/com/android/idegen/ModuleIndexes.java b/tools/idegen/src/com/android/idegen/ModuleIndexes.java
index 890389f..371c2ba 100644
--- a/tools/idegen/src/com/android/idegen/ModuleIndexes.java
+++ b/tools/idegen/src/com/android/idegen/ModuleIndexes.java
@@ -49,7 +49,7 @@
 
         moduleNameToMakeFileMap = Maps.newHashMap();
         makeFileToModuleNamesMap = Maps.newHashMap();
-        logger.info("Building index from " + indexFile.getAbsolutePath());
+        logger.info("Building index from " + indexFile.getCanonicalPath());
         Files.readLines(indexFile, Charset.forName("UTF-8"),
                 new LineProcessor<Object>() {
                     int count = 0;
@@ -84,7 +84,7 @@
             makeFileToModuleNamesMap.put(makeFile, moduleNames);
         } else {
             // Create a aggregate module place holder.
-            //moduleNameToMakeFileMap.put(getAggregateName(moduleName), makeFile);
+            //moduleNameToMakeFileMap.put(getAggregateName(moduleDir), makeFile);
         }
         moduleNames.add(moduleName);
     }
@@ -92,31 +92,7 @@
     public String getMakeFile(String moduleName) {
         Preconditions.checkState(moduleNameToMakeFileMap != null,
                 "Index not built. Call build() first.");
+
         return moduleNameToMakeFileMap.get(moduleName);
     }
-
-    public Set<String> getAggregatedModules(String moduleName) {
-        Preconditions.checkState(makeFileToModuleNamesMap != null,
-                "Index not built. Call build() first.");
-        String makeFile = getMakeFile(moduleName);
-        return makeFileToModuleNamesMap.get(makeFile);
-    }
-
-    public boolean isPartOfAggregatedModule(String moduleName) {
-        String makeFile = getMakeFile(moduleName);
-        if (makeFile == null) {
-            return false;
-        }
-        Set<String> moduleNames = makeFileToModuleNamesMap.get(makeFile);
-        if (moduleNames == null) {
-            return false;
-        }
-        return moduleNames.size() > 1;
-    }
-
-    public String getAggregateName(String moduleName) {
-        String fileName = getMakeFile(moduleName);
-        File file = new File(fileName);
-        return file.getParentFile().getName() + "-aggregate";
-    }
 }
diff --git a/tools/idegen/src/com/android/idegen/StandardModule.java b/tools/idegen/src/com/android/idegen/StandardModule.java
deleted file mode 100644
index f7b24b0..0000000
--- a/tools/idegen/src/com/android/idegen/StandardModule.java
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * 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.android.idegen;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import java.util.Set;
-import java.util.logging.Logger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Module constructed from a make file.
- *
- * TODO: read the make file and understand included source dirs in addition to searching
- * sub-directories.  Make files can include sources that are not sub-directories.  For example,
- * the framework module includes sources from:
- *
- *   external/libphonenumber/java/src
- *
- *   to provide:
- *
- *   com.android.i18n.phonenumbers.PhoneNumberUtil;
- */
-public class StandardModule extends Module {
-
-    static final String REL_OUT_APP_DIR = "out/target/common/obj/APPS";
-
-    private static final Logger logger = Logger.getLogger(StandardModule.class.getName());
-
-    private static final Pattern SRC_PATTERN = Pattern.compile(
-            ".*\\(call all-java-files-under, (.*)\\)");
-    private static final String[] AUTO_DEPENDENCIES = new String[]{
-            IntellijProject.FRAMEWORK_MODULE, "libcore"
-    };
-    private static final String[] DIRS_WITH_AUTO_DEPENDENCIES = new String[]{
-            "packages", "vendor", "frameworks/ex", "frameworks/opt", "frameworks/support"
-    };
-
-    String moduleName;
-    File makeFile;
-    File moduleRoot;
-    File repoRoot;
-
-    Set<String> directDependencies = Sets.newHashSet();
-
-    File intermediatesDir;
-    MakeFileParser makeFileParser;
-    boolean searchForSrc;
-
-    public StandardModule(String moduleName, String makeFile) {
-        this(moduleName, new File(makeFile), false);
-    }
-
-    public StandardModule(String moduleName, String makeFile, boolean searchForSrc) {
-        this(Preconditions.checkNotNull(moduleName), new File(Preconditions.checkNotNull(makeFile)),
-                searchForSrc);
-    }
-
-    public StandardModule(String moduleName, File makeFile, boolean searchForSrc) {
-        this.moduleName = moduleName;
-        this.makeFile = makeFile;
-        this.moduleRoot = makeFile.getParentFile();
-        this.repoRoot = DirectorySearch.findRepoRoot(makeFile);
-        this.intermediatesDir = new File(repoRoot.getAbsolutePath() + File.separator +
-                REL_OUT_APP_DIR + File.separator + getName() + "_intermediates" +
-                File.separator + "src");
-        this.searchForSrc = searchForSrc;
-
-        // TODO: auto-detect when framework dependency is needed instead of using coded list.
-        for (String dir : DIRS_WITH_AUTO_DEPENDENCIES) {
-            // length + 2 to account for slash
-            boolean isDir = makeFile.getAbsolutePath().startsWith(repoRoot + "/" + dir);
-            if (isDir) {
-                for (String dependency : AUTO_DEPENDENCIES) {
-                    this.directDependencies.add(dependency);
-                }
-            }
-        }
-
-        makeFileParser = new MakeFileParser(makeFile, moduleName);
-    }
-
-    protected void build() throws IOException {
-        makeFileParser.parse();
-        buildDependencyList();
-        buildDependentModules();
-        //buildImlFile();
-        logger.info("Done building module " + moduleName);
-        logger.info(toString());
-    }
-
-    @Override
-    protected File getDir() {
-        return moduleRoot;
-    }
-
-    @Override
-    protected String getName() {
-        return moduleName;
-    }
-
-    @Override
-    protected List<File> getIntermediatesDirs() {
-        return Lists.newArrayList(intermediatesDir);
-    }
-
-    @Override
-    public File getRepoRoot() {
-        return this.repoRoot;
-    }
-
-    public Set<String> getDirectDependencies() {
-        return this.directDependencies;
-    }
-
-    @Override
-    protected ImmutableList<File> getSourceDirs() {
-        ImmutableList<File> srcDirs;
-        if (searchForSrc) {
-            srcDirs = DirectorySearch.findSourceDirs(makeFile);
-        } else {
-            srcDirs = parseSourceFiles(makeFile);
-        }
-        return srcDirs;
-    }
-
-    @Override
-    protected ImmutableList<File> getExcludeDirs() {
-        return DirectorySearch.findExcludeDirs(makeFile);
-    }
-
-    @Override
-    protected boolean isAndroidModule() {
-        File manifest = new File(moduleRoot, "AndroidManifest.xml");
-        return manifest.exists();
-    }
-
-    private ImmutableList<File> parseSourceFiles(File root) {
-        ImmutableList.Builder<File> builder = ImmutableList.builder();
-        File rootDir;
-        if (root.isFile()) {
-            rootDir = root.getParentFile();
-        } else {
-            rootDir = root;
-        }
-
-        Iterable<String> values = makeFileParser.getValues(Key.LOCAL_SRC_FILES.name());
-        if (values != null) {
-            for (String value : values) {
-                Matcher matcher = SRC_PATTERN.matcher(value);
-                if (matcher.matches()) {
-                    String dir = matcher.group(1);
-                    builder.add(new File(rootDir, dir));
-                } else if (value.contains("/")) {
-                    // Treat as individual file.
-                    builder.add(new File(rootDir, value));
-                }
-            }
-        }
-        return builder.build();
-    }
-
-    private void buildDependencyList() {
-        parseDirectDependencies(Key.LOCAL_STATIC_JAVA_LIBRARIES);
-        parseDirectDependencies(Key.LOCAL_JAVA_LIBRARIES);
-    }
-
-    private void parseDirectDependencies(Key key) {
-        Iterable<String> names = makeFileParser.getValues(key.name());
-        if (names != null) {
-            for (String dependency : names) {
-                directDependencies.add(dependency);
-            }
-        }
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(getName());
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null || getClass() != obj.getClass()) {
-            return false;
-        }
-        StandardModule other = (StandardModule) obj;
-        return Objects.equal(getName(), other.getName());
-    }
-
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this)
-                .add("super", super.toString())
-                .add("makeFileParser", makeFileParser)
-                .add("directDependencies", Iterables.toString(directDependencies))
-                .toString();
-    }
-}
diff --git a/tools/recovery_l10n/res/values-be/strings.xml b/tools/recovery_l10n/res/values-az-rAZ/strings.xml
similarity index 61%
copy from tools/recovery_l10n/res/values-be/strings.xml
copy to tools/recovery_l10n/res/values-az-rAZ/strings.xml
index 5f48a2d..3435573 100644
--- a/tools/recovery_l10n/res/values-be/strings.xml
+++ b/tools/recovery_l10n/res/values-az-rAZ/strings.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="recovery_installing" msgid="7864047928003865598">"Усталёўка абнаўлення сістэмы..."</string>
-    <string name="recovery_erasing" msgid="4612809744968710197">"Выдаленне..."</string>
-    <string name="recovery_no_command" msgid="1915703879031023455">"Няма каманды"</string>
-    <string name="recovery_error" msgid="4550265746256727080">"Памылка"</string>
+    <string name="recovery_installing" msgid="7864047928003865598">"Sistem güncəlləməsi quraşdırılır..."</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"Silinir..."</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"Əmr yoxdur."</string>
+    <string name="recovery_error" msgid="4550265746256727080">"Xəta!"</string>
 </resources>
diff --git a/tools/recovery_l10n/res/values-be/strings.xml b/tools/recovery_l10n/res/values-az/strings.xml
similarity index 61%
copy from tools/recovery_l10n/res/values-be/strings.xml
copy to tools/recovery_l10n/res/values-az/strings.xml
index 5f48a2d..3435573 100644
--- a/tools/recovery_l10n/res/values-be/strings.xml
+++ b/tools/recovery_l10n/res/values-az/strings.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="recovery_installing" msgid="7864047928003865598">"Усталёўка абнаўлення сістэмы..."</string>
-    <string name="recovery_erasing" msgid="4612809744968710197">"Выдаленне..."</string>
-    <string name="recovery_no_command" msgid="1915703879031023455">"Няма каманды"</string>
-    <string name="recovery_error" msgid="4550265746256727080">"Памылка"</string>
+    <string name="recovery_installing" msgid="7864047928003865598">"Sistem güncəlləməsi quraşdırılır..."</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"Silinir..."</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"Əmr yoxdur."</string>
+    <string name="recovery_error" msgid="4550265746256727080">"Xəta!"</string>
 </resources>
diff --git a/tools/recovery_l10n/res/values-be/strings.xml b/tools/recovery_l10n/res/values-en-rIN/strings.xml
similarity index 61%
copy from tools/recovery_l10n/res/values-be/strings.xml
copy to tools/recovery_l10n/res/values-en-rIN/strings.xml
index 5f48a2d..b70d678c 100644
--- a/tools/recovery_l10n/res/values-be/strings.xml
+++ b/tools/recovery_l10n/res/values-en-rIN/strings.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="recovery_installing" msgid="7864047928003865598">"Усталёўка абнаўлення сістэмы..."</string>
-    <string name="recovery_erasing" msgid="4612809744968710197">"Выдаленне..."</string>
-    <string name="recovery_no_command" msgid="1915703879031023455">"Няма каманды"</string>
-    <string name="recovery_error" msgid="4550265746256727080">"Памылка"</string>
+    <string name="recovery_installing" msgid="7864047928003865598">"Installing system update…"</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"Erasing…"</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"No command."</string>
+    <string name="recovery_error" msgid="4550265746256727080">"Error!"</string>
 </resources>
diff --git a/tools/recovery_l10n/res/values-et/strings.xml b/tools/recovery_l10n/res/values-et-rEE/strings.xml
similarity index 100%
rename from tools/recovery_l10n/res/values-et/strings.xml
rename to tools/recovery_l10n/res/values-et-rEE/strings.xml
diff --git a/tools/recovery_l10n/res/values-be/strings.xml b/tools/recovery_l10n/res/values-fr-rCA/strings.xml
similarity index 61%
copy from tools/recovery_l10n/res/values-be/strings.xml
copy to tools/recovery_l10n/res/values-fr-rCA/strings.xml
index 5f48a2d..f2a85d8 100644
--- a/tools/recovery_l10n/res/values-be/strings.xml
+++ b/tools/recovery_l10n/res/values-fr-rCA/strings.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="recovery_installing" msgid="7864047928003865598">"Усталёўка абнаўлення сістэмы..."</string>
-    <string name="recovery_erasing" msgid="4612809744968710197">"Выдаленне..."</string>
-    <string name="recovery_no_command" msgid="1915703879031023455">"Няма каманды"</string>
-    <string name="recovery_error" msgid="4550265746256727080">"Памылка"</string>
+    <string name="recovery_installing" msgid="7864047928003865598">"Installation de la mise à jour du système en cours…"</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"Effacement en cours…"</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"Aucune commande."</string>
+    <string name="recovery_error" msgid="4550265746256727080">"Erreur!"</string>
 </resources>
diff --git a/tools/recovery_l10n/res/values-hi/strings.xml b/tools/recovery_l10n/res/values-hi/strings.xml
index 3dfab3e..a470d12 100644
--- a/tools/recovery_l10n/res/values-hi/strings.xml
+++ b/tools/recovery_l10n/res/values-hi/strings.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="recovery_installing" msgid="7864047928003865598">"सिस्टम अपडेट इंस्टॉल कर रहा है…"</string>
+    <string name="recovery_installing" msgid="7864047928003865598">"सिस्टम के बारे में नई जानकारी मिल रही है…"</string>
     <string name="recovery_erasing" msgid="4612809744968710197">"मिटा रहा है…"</string>
     <string name="recovery_no_command" msgid="1915703879031023455">"कोई आदेश नहीं."</string>
     <string name="recovery_error" msgid="4550265746256727080">"त्रुटि!"</string>
diff --git a/tools/recovery_l10n/res/values-be/strings.xml b/tools/recovery_l10n/res/values-hy-rAM/strings.xml
similarity index 61%
copy from tools/recovery_l10n/res/values-be/strings.xml
copy to tools/recovery_l10n/res/values-hy-rAM/strings.xml
index 5f48a2d..7babe80 100644
--- a/tools/recovery_l10n/res/values-be/strings.xml
+++ b/tools/recovery_l10n/res/values-hy-rAM/strings.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="recovery_installing" msgid="7864047928003865598">"Усталёўка абнаўлення сістэмы..."</string>
-    <string name="recovery_erasing" msgid="4612809744968710197">"Выдаленне..."</string>
-    <string name="recovery_no_command" msgid="1915703879031023455">"Няма каманды"</string>
-    <string name="recovery_error" msgid="4550265746256727080">"Памылка"</string>
+    <string name="recovery_installing" msgid="7864047928003865598">"Համակարգի թարմացման տեղադրում…"</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"Ջնջում…"</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"Հրամանը տրված չէ:"</string>
+    <string name="recovery_error" msgid="4550265746256727080">"Սխալ"</string>
 </resources>
diff --git a/tools/recovery_l10n/res/values-ka-rGE/strings.xml b/tools/recovery_l10n/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..2d27c17
--- /dev/null
+++ b/tools/recovery_l10n/res/values-ka-rGE/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recovery_installing" msgid="7864047928003865598">"სისტემის განახლების დაყენება…"</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"მიმდინარეობს წაშლა…"</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"ბრძანება არ არის."</string>
+    <string name="recovery_error" msgid="4550265746256727080">"შეცდომა!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-km-rKH/strings.xml b/tools/recovery_l10n/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..0c1c272
--- /dev/null
+++ b/tools/recovery_l10n/res/values-km-rKH/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recovery_installing" msgid="7864047928003865598">"កំពុង​ដំឡើង​បច្ចុប្បន្នភាព​ប្រព័ន្ធ…"</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"កំពុង​លុប…"</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"គ្មាន​ពាក្យ​បញ្ជា។"</string>
+    <string name="recovery_error" msgid="4550265746256727080">"កំហុស!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-lo-rLA/strings.xml b/tools/recovery_l10n/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..5880cca
--- /dev/null
+++ b/tools/recovery_l10n/res/values-lo-rLA/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recovery_installing" msgid="7864047928003865598">"ກຳລັງຕິດຕັ້ງການອັບເດດລະບົບ..."</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"ກຳລັງລຶບ..."</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"ບໍ່ມີຄຳສັ່ງ."</string>
+    <string name="recovery_error" msgid="4550265746256727080">"ຜິດພາດ!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-be/strings.xml b/tools/recovery_l10n/res/values-mn-rMN/strings.xml
similarity index 69%
rename from tools/recovery_l10n/res/values-be/strings.xml
rename to tools/recovery_l10n/res/values-mn-rMN/strings.xml
index 5f48a2d..463cafe 100644
--- a/tools/recovery_l10n/res/values-be/strings.xml
+++ b/tools/recovery_l10n/res/values-mn-rMN/strings.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="recovery_installing" msgid="7864047928003865598">"Усталёўка абнаўлення сістэмы..."</string>
-    <string name="recovery_erasing" msgid="4612809744968710197">"Выдаленне..."</string>
-    <string name="recovery_no_command" msgid="1915703879031023455">"Няма каманды"</string>
-    <string name="recovery_error" msgid="4550265746256727080">"Памылка"</string>
+    <string name="recovery_installing" msgid="7864047928003865598">"Системийн шинэчлэлтийг суулгаж байна…"</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"Арилгаж байна…"</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"Команд байхгүй."</string>
+    <string name="recovery_error" msgid="4550265746256727080">"Алдаа!"</string>
 </resources>
diff --git a/tools/recovery_l10n/res/values-ms/strings.xml b/tools/recovery_l10n/res/values-ms-rMY/strings.xml
similarity index 100%
rename from tools/recovery_l10n/res/values-ms/strings.xml
rename to tools/recovery_l10n/res/values-ms-rMY/strings.xml
diff --git a/tools/recovery_l10n/res/values-ne-rNP/strings.xml b/tools/recovery_l10n/res/values-ne-rNP/strings.xml
new file mode 100644
index 0000000..835f275
--- /dev/null
+++ b/tools/recovery_l10n/res/values-ne-rNP/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recovery_installing" msgid="7864047928003865598">"प्रणाली अद्यावधिक स्थापना गर्दै..."</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"मेटाइदै..."</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"कुनै आदेश छैन।"</string>
+    <string name="recovery_error" msgid="4550265746256727080">"त्रुटि!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-ne/strings.xml b/tools/recovery_l10n/res/values-ne/strings.xml
new file mode 100644
index 0000000..835f275
--- /dev/null
+++ b/tools/recovery_l10n/res/values-ne/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recovery_installing" msgid="7864047928003865598">"प्रणाली अद्यावधिक स्थापना गर्दै..."</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"मेटाइदै..."</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"कुनै आदेश छैन।"</string>
+    <string name="recovery_error" msgid="4550265746256727080">"त्रुटि!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-si-rLK/strings.xml b/tools/recovery_l10n/res/values-si-rLK/strings.xml
new file mode 100644
index 0000000..e717a97
--- /dev/null
+++ b/tools/recovery_l10n/res/values-si-rLK/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recovery_installing" msgid="7864047928003865598">"පද්ධති යාවත්කාල ස්ථාපනය කරමින්…"</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"මකමින්...."</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"විධානයක් නොමැත."</string>
+    <string name="recovery_error" msgid="4550265746256727080">"දෝෂය!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-si/strings.xml b/tools/recovery_l10n/res/values-si/strings.xml
new file mode 100644
index 0000000..e717a97
--- /dev/null
+++ b/tools/recovery_l10n/res/values-si/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recovery_installing" msgid="7864047928003865598">"පද්ධති යාවත්කාල ස්ථාපනය කරමින්…"</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"මකමින්...."</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"විධානයක් නොමැත."</string>
+    <string name="recovery_error" msgid="4550265746256727080">"දෝෂය!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-be/strings.xml b/tools/recovery_l10n/res/values-zh-rHK/strings.xml
similarity index 61%
copy from tools/recovery_l10n/res/values-be/strings.xml
copy to tools/recovery_l10n/res/values-zh-rHK/strings.xml
index 5f48a2d..f615c7a 100644
--- a/tools/recovery_l10n/res/values-be/strings.xml
+++ b/tools/recovery_l10n/res/values-zh-rHK/strings.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="recovery_installing" msgid="7864047928003865598">"Усталёўка абнаўлення сістэмы..."</string>
-    <string name="recovery_erasing" msgid="4612809744968710197">"Выдаленне..."</string>
-    <string name="recovery_no_command" msgid="1915703879031023455">"Няма каманды"</string>
-    <string name="recovery_error" msgid="4550265746256727080">"Памылка"</string>
+    <string name="recovery_installing" msgid="7864047928003865598">"正在安裝系統更新…"</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"正在清除…"</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"沒有指令。"</string>
+    <string name="recovery_error" msgid="4550265746256727080">"錯誤!"</string>
 </resources>
diff --git a/tools/rmtypedefs/.gitignore b/tools/rmtypedefs/.gitignore
new file mode 100644
index 0000000..04d423f
--- /dev/null
+++ b/tools/rmtypedefs/.gitignore
@@ -0,0 +1,3 @@
+out
+.idea/workspace.xml
+.DS_Store
diff --git a/tools/rmtypedefs/.idea/compiler.xml b/tools/rmtypedefs/.idea/compiler.xml
new file mode 100644
index 0000000..217af47
--- /dev/null
+++ b/tools/rmtypedefs/.idea/compiler.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <option name="DEFAULT_COMPILER" value="Javac" />
+    <resourceExtensions />
+    <wildcardResourcePatterns>
+      <entry name="!?*.java" />
+      <entry name="!?*.form" />
+      <entry name="!?*.class" />
+      <entry name="!?*.groovy" />
+      <entry name="!?*.scala" />
+      <entry name="!?*.flex" />
+      <entry name="!?*.kt" />
+      <entry name="!?*.clj" />
+    </wildcardResourcePatterns>
+    <annotationProcessing>
+      <profile default="true" name="Default" enabled="false">
+        <processorPath useClasspath="true" />
+      </profile>
+    </annotationProcessing>
+  </component>
+</project>
+
diff --git a/tools/rmtypedefs/.idea/copyright/profiles_settings.xml b/tools/rmtypedefs/.idea/copyright/profiles_settings.xml
new file mode 100644
index 0000000..3572571
--- /dev/null
+++ b/tools/rmtypedefs/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,5 @@
+<component name="CopyrightManager">
+  <settings default="">
+    <module2copyright />
+  </settings>
+</component>
\ No newline at end of file
diff --git a/tools/rmtypedefs/.idea/encodings.xml b/tools/rmtypedefs/.idea/encodings.xml
new file mode 100644
index 0000000..e206d70
--- /dev/null
+++ b/tools/rmtypedefs/.idea/encodings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
+</project>
+
diff --git a/tools/rmtypedefs/.idea/misc.xml b/tools/rmtypedefs/.idea/misc.xml
new file mode 100644
index 0000000..9732041
--- /dev/null
+++ b/tools/rmtypedefs/.idea/misc.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="EntryPointsManager">
+    <entry_points version="2.0" />
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/out" />
+  </component>
+</project>
+
diff --git a/tools/rmtypedefs/.idea/modules.xml b/tools/rmtypedefs/.idea/modules.xml
new file mode 100644
index 0000000..52f04c3
--- /dev/null
+++ b/tools/rmtypedefs/.idea/modules.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/rmtypedefs.iml" filepath="$PROJECT_DIR$/rmtypedefs.iml" />
+    </modules>
+  </component>
+</project>
+
diff --git a/tools/rmtypedefs/.idea/scopes/scope_settings.xml b/tools/rmtypedefs/.idea/scopes/scope_settings.xml
new file mode 100644
index 0000000..922003b
--- /dev/null
+++ b/tools/rmtypedefs/.idea/scopes/scope_settings.xml
@@ -0,0 +1,5 @@
+<component name="DependencyValidationManager">
+  <state>
+    <option name="SKIP_IMPORT_STATEMENTS" value="false" />
+  </state>
+</component>
\ No newline at end of file
diff --git a/tools/rmtypedefs/.idea/uiDesigner.xml b/tools/rmtypedefs/.idea/uiDesigner.xml
new file mode 100644
index 0000000..3b00020
--- /dev/null
+++ b/tools/rmtypedefs/.idea/uiDesigner.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Palette2">
+    <group name="Swing">
+      <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+      </item>
+      <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
+        <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+        <initial-values>
+          <property name="text" value="Button" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="RadioButton" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="CheckBox" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="Label" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+          <preferred-size width="-1" height="20" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+      </item>
+    </group>
+  </component>
+</project>
+
diff --git a/tools/rmtypedefs/.idea/vcs.xml b/tools/rmtypedefs/.idea/vcs.xml
new file mode 100644
index 0000000..a5dd086
--- /dev/null
+++ b/tools/rmtypedefs/.idea/vcs.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="" vcs="" />
+    <mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
+  </component>
+</project>
+
diff --git a/tools/rmtypedefs/Android.mk b/tools/rmtypedefs/Android.mk
new file mode 100644
index 0000000..d79d2ff
--- /dev/null
+++ b/tools/rmtypedefs/Android.mk
@@ -0,0 +1,46 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+# We use copy-file-to-new-target so that the installed
+# script file's timestamp is at least as new as the
+# .jar file it wraps.
+
+# the execution script
+# ============================================================
+include $(CLEAR_VARS)
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE := rmtypedefs
+
+#LOCAL_STATIC_JAVA_LIBRARIES := \
+#        asm-tools \
+#        guavalib
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): $(HOST_OUT_JAVA_LIBRARIES)/rmtypedefs$(COMMON_JAVA_PACKAGE_SUFFIX)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/rmtypedefs | $(ACP)
+	@echo "Copy: $(PRIVATE_MODULE) ($@)"
+	$(copy-file-to-new-target)
+	$(hide) chmod 755 $@
+
+# the other stuff
+# ============================================================
+subdirs := $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
+		src \
+	))
+
+include $(subdirs)
diff --git a/tools/rmtypedefs/README.txt b/tools/rmtypedefs/README.txt
new file mode 100644
index 0000000..9f3fb8b
--- /dev/null
+++ b/tools/rmtypedefs/README.txt
@@ -0,0 +1,13 @@
+Android TypeDef Remover 1.0
+
+This utility finds and removes all .class files that have been
+annotated with the @IntDef annotation (android.annotations.IntDef) or
+the @StringDef annotation (android.annotations.StringDef).
+
+It also makes sure that these annotations have source level retention
+(@Retention(RetentionPolicy.SOURCE)), since otherwise uses of the
+typedef will appear in .class files as well.
+
+This is intended to be used during the build to strip out any typedef
+annotation classes, since these are not needed (or desirable) in the
+system image.
diff --git a/tools/rmtypedefs/etc/manifest.txt b/tools/rmtypedefs/etc/manifest.txt
new file mode 100644
index 0000000..39f2e29
--- /dev/null
+++ b/tools/rmtypedefs/etc/manifest.txt
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+Main-Class: com.android.tools.rmtypedefs.RmTypeDefs
diff --git a/tools/rmtypedefs/etc/rmtypedefs b/tools/rmtypedefs/etc/rmtypedefs
new file mode 100755
index 0000000..bc0cbe2
--- /dev/null
+++ b/tools/rmtypedefs/etc/rmtypedefs
@@ -0,0 +1,46 @@
+#!/bin/bash
+#
+# 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.
+
+# Set up prog to be the path of this script, including following symlinks,
+# and set up progdir to be the fully-qualified pathname of its directory.
+prog="$0"
+while [ -h "${prog}" ]; do
+    newProg=`/bin/ls -ld "${prog}"`
+    newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
+    if expr "x${newProg}" : 'x/' >/dev/null; then
+        prog="${newProg}"
+    else
+        progdir=`dirname "${prog}"`
+        prog="${progdir}/${newProg}"
+    fi
+done
+oldwd=`pwd`
+progdir=`dirname "${prog}"`
+cd "${progdir}"
+progdir=`pwd`
+prog="${progdir}"/`basename "${prog}"`
+cd "${oldwd}"
+
+libdir=`dirname $progdir`/framework
+
+javaOpts=""
+while expr "x$1" : 'x-J' >/dev/null; do
+    opt=`expr "$1" : '-J\(.*\)'`
+    javaOpts="${javaOpts} -${opt}"
+    shift
+done
+
+exec java $javaOpts -jar $libdir/rmtypedefs.jar "$@"
diff --git a/tools/rmtypedefs/rmtypedefs.iml b/tools/rmtypedefs/rmtypedefs.iml
new file mode 100644
index 0000000..6e0f0fc
--- /dev/null
+++ b/tools/rmtypedefs/rmtypedefs.iml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="false">
+    <output url="file://$MODULE_DIR$/../../../out/rmtypedefs" />
+    <output-test url="file://$MODULE_DIR$/../../../out/rmtypedefs" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/asm-tools/asm-4.0.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/asm-tools/src-4.0.zip!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/guava-tools/guava-13.0.1.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/guava-tools/src.zip!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+  </component>
+</module>
+
diff --git a/tools/rmtypedefs/src/Android.mk b/tools/rmtypedefs/src/Android.mk
new file mode 100644
index 0000000..067a2e6
--- /dev/null
+++ b/tools/rmtypedefs/src/Android.mk
@@ -0,0 +1,31 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+
+# rmtypedefs java library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_JAR_MANIFEST := ../etc/manifest.txt
+LOCAL_STATIC_JAVA_LIBRARIES := \
+        asm-tools \
+        guava-tools
+
+LOCAL_MODULE:= rmtypedefs
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
diff --git a/tools/rmtypedefs/src/com/android/tools/rmtypedefs/RmTypeDefs.java b/tools/rmtypedefs/src/com/android/tools/rmtypedefs/RmTypeDefs.java
new file mode 100644
index 0000000..9375590
--- /dev/null
+++ b/tools/rmtypedefs/src/com/android/tools/rmtypedefs/RmTypeDefs.java
@@ -0,0 +1,224 @@
+/*
+ * 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.android.tools.rmtypedefs;
+
+import com.google.common.io.Files;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.objectweb.asm.Opcodes.ASM4;
+
+/**
+ * Finds and deletes typedef annotation classes (and also warns if their
+ * retention was wrong, such that uses embeds
+ */
+public class RmTypeDefs {
+
+    private static final String ANNOTATION = "java/lang/annotation/Annotation";
+    private static final String STRING_DEF = "android/annotation/StringDef";
+    private static final String INT_DEF = "android/annotation/IntDef";
+    private static final String INT_DEF_DESC = "L" + INT_DEF + ";";
+    private static final String STRING_DEF_DESC = "L" + STRING_DEF + ";";
+    private static final String RETENTION_DESC = "Ljava/lang/annotation/Retention;";
+    private static final String RETENTION_POLICY_DESC = "Ljava/lang/annotation/RetentionPolicy;";
+    private static final String SOURCE_RETENTION_VALUE = "SOURCE";
+
+    private boolean mQuiet;
+    private boolean mVerbose;
+    private boolean mHaveError;
+    private boolean mDryRun;
+
+    public static void main(String[] args) {
+        new RmTypeDefs().run(args);
+    }
+
+    private void run(String[] args) {
+        if (args.length == 0) {
+            usage(System.err);
+            System.exit(1);
+        }
+
+        List<File> dirs = new ArrayList<File>();
+        for (String arg : args) {
+            if (arg.equals("--help") || arg.equals("-h")) {
+                usage(System.out);
+                return;
+            } else if (arg.equals("-q") || arg.equals("--quiet") || arg.equals("--silent")) {
+                mQuiet = true;
+            } else if (arg.equals("-v") || arg.equals("--verbose")) {
+                mVerbose = true;
+            } else if (arg.equals("-n") || arg.equals("--dry-run")) {
+                mDryRun = true;
+            } else if (arg.startsWith("-")) {
+                System.err.println("Unknown argument " + arg);
+                usage(System.err);
+                System.exit(1);
+
+            } else {
+                // Other arguments should be file names
+                File file = new File(arg);
+                if (file.exists()) {
+                    dirs.add(file);
+                } else {
+                    System.err.println(file + " does not exist");
+                    usage(System.err);
+                    System.exit(1);
+                }
+            }
+        }
+
+        if (!mQuiet) {
+            System.out.println("Deleting @IntDef and @StringDef annotation class files");
+        }
+
+        for (File dir : dirs) {
+            find(dir);
+        }
+
+        System.exit(mHaveError ? -1 : 0);
+    }
+
+    private void find(File file) {
+        if (file.isDirectory()) {
+            File[] files = file.listFiles();
+            if (files != null) {
+                for (File f : files) {
+                    find(f);
+                }
+            }
+        } else if (file.isFile()) {
+            String path = file.getPath();
+            if (path.endsWith(".class")) {
+                checkClass(file);
+            } else if (path.endsWith(".jar")) {
+                System.err.println(path + ": Warning: Encountered .jar file; .class files "
+                        + "are not scanned and removed inside .jar files");
+            }
+        }
+    }
+
+    private void checkClass(File file) {
+        try {
+            byte[] bytes = Files.toByteArray(file);
+            ClassReader classReader = new ClassReader(bytes);
+            classReader.accept(new MyVisitor(file), 0);
+        } catch (IOException e) {
+            System.err.println("Could not read " + file + ": " + e.getLocalizedMessage());
+            System.exit(1);
+        }
+    }
+
+    /**
+     * Prints usage statement.
+     */
+    static void usage(PrintStream out) {
+        out.println("Android TypeDef Remover 1.0");
+        out.println("Copyright (C) 2013 The Android Open Source Project\n");
+        out.println("Usage: rmtypedefs folder1 [folder2 [folder3...]]\n");
+        out.println("Options:");
+        out.println("  -h,--help                  show this message");
+        out.println("  -q,--quiet                 quiet");
+        out.println("  -v,--verbose               verbose");
+        out.println("  -n,--dry-run               dry-run only, leaves files alone");
+    }
+
+    private class MyVisitor extends ClassVisitor {
+
+        /** Class file name */
+        private File mFile;
+
+        /** Class name */
+        private String mName;
+
+        /** Is this class an annotation? */
+        private boolean mAnnotation;
+
+        /** Is this annotation a typedef? Only applies if {@link #mAnnotation} */
+        private boolean mTypedef;
+
+        /** Does the annotation have source retention? Only applies if {@link #mAnnotation} */
+        private boolean mSourceRetention;
+
+        public MyVisitor(File file) {
+            super(ASM4);
+            mFile = file;
+        }
+
+        public void visit(
+                int version,
+                int access,
+                String name,
+                String signature,
+                String superName,
+                String[] interfaces) {
+            mName = name;
+            mAnnotation = interfaces != null && interfaces.length >= 1
+                    && ANNOTATION.equals(interfaces[0]);
+
+            // Special case: Also delete the actual @IntDef and @StringDef .class files.
+            // These have class file retention
+            mTypedef = name.equals(INT_DEF) || name.equals(STRING_DEF);
+        }
+
+        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+            mTypedef = desc.equals(INT_DEF_DESC) || desc.equals(STRING_DEF_DESC);
+            if (desc.equals(RETENTION_DESC)) {
+                return new AnnotationVisitor(ASM4) {
+                    public void visitEnum(String name, String desc, String value) {
+                        if (desc.equals(RETENTION_POLICY_DESC)) {
+                            mSourceRetention = SOURCE_RETENTION_VALUE.equals(value);
+                        }
+                    }
+                };
+            }
+            return null;
+        }
+
+        public void visitEnd() {
+            if (mAnnotation && mTypedef) {
+                if (!mSourceRetention && !mName.equals(STRING_DEF) && !mName.equals(INT_DEF)) {
+                    System.err.println(mFile + ": Warning: Annotation should be annotated "
+                            + "with @Retention(RetentionPolicy.SOURCE)");
+                    mHaveError = true;
+                }
+                if (mVerbose) {
+                    if (mDryRun) {
+                        System.out.println("Would delete " + mFile);
+                    } else {
+                        System.out.println("Deleting " + mFile);
+                    }
+                }
+                if (!mDryRun) {
+                    boolean deleted = mFile.delete();
+                    if (!deleted) {
+                        System.err.println("Could not delete " + mFile);
+                        mHaveError = true;
+                    }
+                }
+            }
+        }
+    }
+}
+
diff --git a/tutorials/MoarRam/README.txt b/tutorials/MoarRam/README.txt
index 028389b..8f1a487 100644
--- a/tutorials/MoarRam/README.txt
+++ b/tutorials/MoarRam/README.txt
@@ -12,3 +12,6 @@
 
 Each allocation can be freed by clicking the corresponding free button in the
 UI.
+
+NOTE 09/16/2013
+A new feature is added to force a double free. Both debug libc and Valgrind can capture it.
diff --git a/tutorials/MoarRam/jni/Android.mk b/tutorials/MoarRam/jni/Android.mk
index 933cbdf..b1eec37 100644
--- a/tutorials/MoarRam/jni/Android.mk
+++ b/tutorials/MoarRam/jni/Android.mk
@@ -41,3 +41,12 @@
 LOCAL_SHARED_LIBRARIES += liblog
 
 include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE    := libmoarram-doublefree
+LOCAL_SRC_FILES := df.c
+LOCAL_SHARED_LIBRARIES += liblog
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/tutorials/MoarRam/jni/df.c b/tutorials/MoarRam/jni/df.c
new file mode 100644
index 0000000..bfea6b8
--- /dev/null
+++ b/tutorials/MoarRam/jni/df.c
@@ -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.
+ *
+ */
+
+#include <jni.h>
+#include <cutils/log.h>
+
+#if defined(LOG_TAG)
+#undef LOG_TAG
+#define LOG_TAG "MOARRAM"
+#endif
+
+void
+Java_com_android_benchmark_moarram_MainActivity_forceDoubleFreeNative(
+    JNIEnv*  env,
+    jobject  this)
+{
+    char *ptr = (char *) malloc(4);
+    *ptr = 0;
+    ALOGW("About to double free %p", ptr);
+    free(ptr);
+    free(ptr);
+}
diff --git a/tutorials/MoarRam/res/layout/activity_main.xml b/tutorials/MoarRam/res/layout/activity_main.xml
index 8319bd7..50b6745 100644
--- a/tutorials/MoarRam/res/layout/activity_main.xml
+++ b/tutorials/MoarRam/res/layout/activity_main.xml
@@ -101,4 +101,19 @@
         android:layout_weight="1"
         android:onClick="freeVariableSizedBlocks" />
     </LinearLayout>
+
+    <LinearLayout
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:orientation="horizontal">
+
+    <Button
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:text="@string/force_double_free"
+        android:layout_weight="1"
+        android:onClick="forceDoubleFree" />
+    </LinearLayout>
+
 </LinearLayout>
diff --git a/tutorials/MoarRam/res/values/strings.xml b/tutorials/MoarRam/res/values/strings.xml
index 0c0031d..e289fd8 100644
--- a/tutorials/MoarRam/res/values/strings.xml
+++ b/tutorials/MoarRam/res/values/strings.xml
@@ -13,4 +13,5 @@
     <string name="free_variable">Free 17 or 71 bytes</string>
     <string name="_17byte">17 bytes</string>
     <string name="_71byte">71 bytes</string>
+    <string name="force_double_free">Force a Double Free</string>
 </resources>
diff --git a/tutorials/MoarRam/src/com/android/benchmark/moarram/MainActivity.java b/tutorials/MoarRam/src/com/android/benchmark/moarram/MainActivity.java
index aa83b8c..0b7dcbc 100644
--- a/tutorials/MoarRam/src/com/android/benchmark/moarram/MainActivity.java
+++ b/tutorials/MoarRam/src/com/android/benchmark/moarram/MainActivity.java
@@ -14,6 +14,7 @@
         System.loadLibrary("moarram-32");
         System.loadLibrary("moarram-2M");
         System.loadLibrary("moarram-17_71");
+        System.loadLibrary("moarram-doublefree");
         setContentView(R.layout.activity_main);
     }
 
@@ -55,10 +56,15 @@
         freeVariableSizedBlocksNative(sizeId == R.id.radio17 ? 0 : 1);
     }
 
+    public void forceDoubleFree(View view) {
+        forceDoubleFreeNative();
+    }
+
     public native void add32ByteBlocksNative();
     public native void free32ByteBlocksNative();
     public native void add2MByteBlocksNative();
     public native void free2MByteBlocksNative();
     public native void addVariableSizedBlocksNative(int sizeId);
     public native void freeVariableSizedBlocksNative(int sizeId);
+    public native void forceDoubleFreeNative();
 }