am a8e6166f: Merge "build: rename LOCAL_32BIT_ONLY to LOCAL_32_BIT_ONLY"

* commit 'a8e6166fa482782719dce28a9ae1869f017e7cee':
  build: rename LOCAL_32BIT_ONLY to LOCAL_32_BIT_ONLY
diff --git a/CleanSpec.mk b/CleanSpec.mk
index c912497..c0525ad 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -208,6 +208,9 @@
 # 4.4.1
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
 
+# 4.4.2
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
+
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/core/Makefile b/core/Makefile
index 2bcf0cf..9f35254 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -902,11 +902,6 @@
 .PHONY: stnod
 stnod: systemtarball-nodeps
 
-# For platform-java goal, add platform as well
-ifneq (,$(filter platform-java, $(MAKECMDGOALS)))
-PLATFORM_ZIP_ADD_JAVA := true
-endif
-
 #######
 ## platform.zip: system, plus other files to be used in PDK fusion build,
 ## in a zip file
@@ -923,7 +918,7 @@
 		$(TARGET_COPY_OUT_SYSTEM) \
 		$(patsubst $(PRODUCT_OUT)/%, %, $(TARGET_OUT_NOTICE_FILES)) \
 		$(addprefix symbols/,$(PDK_SYMBOL_FILES_LIST))
-ifeq (true,$(PLATFORM_ZIP_ADD_JAVA))
+ifneq ($(PDK_PLATFORM_JAVA_ZIP_CONTENTS),)
 	$(hide) cd $(OUT_DIR) && zip -qry $(patsubst $(OUT_DIR)/%,%,$@) $(PDK_PLATFORM_JAVA_ZIP_CONTENTS)
 endif
 ifneq ($(PDK_PLATFORM_ZIP_PRODUCT_BINARIES),)
@@ -1259,6 +1254,7 @@
 	@# build them.
 	$(hide) mkdir -p $(zip_root)/META
 	$(hide) $(ACP) $(APKCERTS_FILE) $(zip_root)/META/apkcerts.txt
+	$(hide) if test -e $(tool_extensions)/releasetools.py; then $(ACP) $(tool_extensions)/releasetools.py $(zip_root)/META/; fi
 	$(hide)	echo "$(PRODUCT_OTA_PUBLIC_KEYS)" > $(zip_root)/META/otakeys.txt
 	$(hide) echo "recovery_api_version=$(PRIVATE_RECOVERY_API_VERSION)" > $(zip_root)/META/misc_info.txt
 	$(hide) echo "fstab_version=$(PRIVATE_RECOVERY_FSTAB_VERSION)" >> $(zip_root)/META/misc_info.txt
@@ -1278,6 +1274,7 @@
 endif
 	$(hide) echo 'mkbootimg_args=$(BOARD_MKBOOTIMG_ARGS)' >> $(zip_root)/META/misc_info.txt
 	$(hide) echo "use_set_metadata=1" >> $(zip_root)/META/misc_info.txt
+	$(hide) echo "multistage_support=1" >> $(zip_root)/META/misc_info.txt
 	$(hide) echo "update_rename_support=1" >> $(zip_root)/META/misc_info.txt
 	$(call generate-userimage-prop-dictionary, $(zip_root)/META/misc_info.txt)
 	@# Zip everything up, preserving symlinks
diff --git a/core/droiddoc.mk b/core/droiddoc.mk
index f528ee0..93b56d4 100644
--- a/core/droiddoc.mk
+++ b/core/droiddoc.mk
@@ -233,6 +233,8 @@
 	@mkdir -p $(dir $@)
 	$(hide) ( F=$$(pwd)/$@ ; cd $(PRIVATE_DOCS_DIR) && zip -rq $$F * )
 
+$(LOCAL_MODULE)-docs.zip : $(out_zip)
+
 $(call dist-for-goals,docs,$(out_zip))
 
 endif
diff --git a/core/multi_prebuilt.mk b/core/multi_prebuilt.mk
index be60e2f..bc85cea 100644
--- a/core/multi_prebuilt.mk
+++ b/core/multi_prebuilt.mk
@@ -69,7 +69,11 @@
   $(if $(7), \
     $(eval LOCAL_BUILT_MODULE_STEM := $(7)) \
    , \
-    $(eval LOCAL_BUILT_MODULE_STEM := $(notdir $(LOCAL_SRC_FILES))) \
+    $(if $(word 2,$(tw)), \
+      $(eval LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)$(suffix $(LOCAL_SRC_FILES))) \
+     , \
+      $(eval LOCAL_BUILT_MODULE_STEM := $(notdir $(LOCAL_SRC_FILES))) \
+     ) \
    ) \
   $(eval LOCAL_MODULE_SUFFIX := $(suffix $(LOCAL_SRC_FILES))) \
   $(if $(filter user,$(TARGET_BUILD_VARIANT)), \
diff --git a/core/pathmap.mk b/core/pathmap.mk
index feecfbf..faea2a8 100644
--- a/core/pathmap.mk
+++ b/core/pathmap.mk
@@ -108,6 +108,7 @@
         v7/gridlayout \
         v7/appcompat \
         v7/mediarouter \
+        v7/recyclerview \
         v8/renderscript \
         v13
 
diff --git a/core/pdk_config.mk b/core/pdk_config.mk
index 9590d70..b0cccc9 100644
--- a/core/pdk_config.mk
+++ b/core/pdk_config.mk
@@ -37,11 +37,16 @@
 endif  # fusion
 endif  # pdk or fusion
 
+PDK_PLATFORM_JAVA_ZIP_JAVA_TARGET_LIB_DIR :=
+PDK_PLATFORM_JAVA_ZIP_JAVA_HOST_LIB_DIR := \
+	host/common/obj/JAVA_LIBRARIES/bouncycastle-host_intermediates
+PDK_PLATFORM_JAVA_ZIP_CONTENTS :=
+
 ifneq (,$(filter platform-java, $(MAKECMDGOALS))$(PDK_FUSION_PLATFORM_ZIP))
 # additional items to add to platform.zip for platform-java build
 # For these dirs, add classes.jar and javalib.jar from the dir to platform.zip
 # all paths under out dir
-PDK_PLATFORM_JAVA_ZIP_JAVA_LIB_DIR := \
+PDK_PLATFORM_JAVA_ZIP_JAVA_TARGET_LIB_DIR += \
 	target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates \
 	target/common/obj/JAVA_LIBRARIES/core_intermediates \
 	target/common/obj/JAVA_LIBRARIES/core-junit_intermediates \
@@ -52,14 +57,21 @@
 	target/common/obj/JAVA_LIBRARIES/telephony-common_intermediates \
 	target/common/obj/JAVA_LIBRARIES/voip-common_intermediates \
 	target/common/obj/JAVA_LIBRARIES/mms-common_intermediates \
-	target/common/obj/JAVA_LIBRARIES/android-ex-camera2_intermediates
+	target/common/obj/JAVA_LIBRARIES/android-ex-camera2_intermediates \
+	target/common/obj/JAVA_LIBRARIES/android-common_intermediates \
+
 # not java libraries
-PDK_PLATFORM_JAVA_ZIP_CONTENTS := \
+PDK_PLATFORM_JAVA_ZIP_CONTENTS += \
 	target/common/obj/APPS/framework-res_intermediates/package-export.apk \
 	target/common/obj/APPS/framework-res_intermediates/src/R.stamp
+endif # platform-java or FUSION build
+
+PDK_PLATFORM_JAVA_ZIP_JAVA_LIB_DIR := \
+	$(PDK_PLATFORM_JAVA_ZIP_JAVA_TARGET_LIB_DIR) \
+	$(PDK_PLATFORM_JAVA_ZIP_JAVA_HOST_LIB_DIR)
+
 PDK_PLATFORM_JAVA_ZIP_CONTENTS += $(foreach lib_dir,$(PDK_PLATFORM_JAVA_ZIP_JAVA_LIB_DIR),\
     $(lib_dir)/classes.jar $(lib_dir)/javalib.jar)
-endif # platform-java or FUSION build
 
 # check and override java support level
 ifneq ($(TARGET_BUILD_PDK)$(PDK_FUSION_PLATFORM_ZIP),)
@@ -117,6 +129,11 @@
 	$(hide) rm -rf $@
 	$(hide) cp -fpPR $< $@
 
+# implicit rules for host java files
+$(HOST_COMMON_OUT_ROOT)/% : $(_pdk_fusion_intermediates)/host/common/% $(_pdk_fusion_stamp)
+	@mkdir -p $(dir $@)
+	$(hide) cp -fpPR $< $@
+
 ifeq (true,$(TARGET_BUILD_PDK_JAVA_PLATFORM))
 
 PDK_FUSION_OUT_DIR := $(OUT_DIR)
@@ -137,11 +154,11 @@
 target/common/obj/APPS/framework-res_intermediates/package-export.apk))
 
 # javalib.jar should pull classes.jar as classes.jar is not explicitly pulled.
-$(foreach lib_dir,$(PDK_PLATFORM_JAVA_ZIP_JAVA_LIB_DIR),\
+$(foreach lib_dir,$(PDK_PLATFORM_JAVA_ZIP_JAVA_TARGET_LIB_DIR),\
 $(eval $(call JAVA_dependency_template,$(lib_dir)/javalib.jar,\
 $(lib_dir)/classes.jar)))
 
-# implicit rules for all others
+# implicit rules for all other target files
 $(TARGET_COMMON_OUT_ROOT)/% : $(_pdk_fusion_intermediates)/target/common/% $(_pdk_fusion_stamp)
 	@mkdir -p $(dir $@)
 	$(hide) cp -fpPR $< $@
diff --git a/core/tasks/vendor_module_check.mk b/core/tasks/vendor_module_check.mk
index c51a40c..80b05b3 100644
--- a/core/tasks/vendor_module_check.mk
+++ b/core/tasks/vendor_module_check.mk
@@ -22,6 +22,7 @@
         csr \
         elan \
         google \
+        htc \
         imgtec \
         invensense \
         lge \
diff --git a/core/version_defaults.mk b/core/version_defaults.mk
index 40248fc..99283b0 100644
--- a/core/version_defaults.mk
+++ b/core/version_defaults.mk
@@ -41,7 +41,7 @@
   # which is the version that we reveal to the end user.
   # Update this value when the platform version changes (rather
   # than overriding it somewhere else).  Can be an arbitrary string.
-  PLATFORM_VERSION := 4.4.3.2.1.000.000
+  PLATFORM_VERSION := 4.4.2
 endif
 
 ifeq "" "$(PLATFORM_SDK_VERSION)"
diff --git a/target/product/core_tiny.mk b/target/product/core_tiny.mk
new file mode 100644
index 0000000..f19fd88
--- /dev/null
+++ b/target/product/core_tiny.mk
@@ -0,0 +1,103 @@
+#
+# 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.
+#
+# Tiny configuration for small devices such as wearables. Includes base and embedded.
+# No telephony
+
+PRODUCT_PACKAGES := \
+    Bluetooth \
+    CertInstaller \
+    FusedLocation \
+    InputDevices \
+    bluetooth-health \
+    hostapd \
+    wpa_supplicant.conf
+
+PRODUCT_PACKAGES += \
+    audio \
+    clatd \
+    clatd.conf \
+    dhcpcd.conf \
+    network \
+    pand \
+    pppd \
+    sdptool \
+    wpa_supplicant
+
+PRODUCT_PACKAGES += \
+    audio.primary.default \
+    audio_policy.default \
+    local_time.default \
+    power.default
+
+PRODUCT_PACKAGES += \
+    local_time.default
+
+PRODUCT_PACKAGES += \
+    BackupRestoreConfirmation \
+    DefaultContainerService \
+    SettingsProvider \
+    Shell \
+    bu \
+    com.android.location.provider \
+    com.android.location.provider.xml \
+    framework-res \
+    installd \
+    ip \
+    ip-up-vpn \
+    ip6tables \
+    iptables \
+    keystore \
+    keystore.default \
+    libOpenMAXAL \
+    libOpenSLES \
+    libdownmix \
+    libfilterfw \
+    libsqlite_jni \
+    libwilhelm \
+    make_ext4fs \
+    screencap \
+    sensorservice \
+    uiautomator
+
+# The order matters
+PRODUCT_BOOT_JARS := \
+    core \
+    conscrypt \
+    okhttp \
+    core-junit \
+    bouncycastle \
+    ext \
+    framework \
+    framework2 \
+    android.policy \
+    services \
+    apache-xml
+
+PRODUCT_RUNTIMES := runtime_libdvm_default
+
+PRODUCT_PROPERTY_OVERRIDES += \
+    ro.carrier=unknown
+
+MINIMAL_FONT_FOOTPRINT := true
+
+$(call inherit-product-if-exists, frameworks/base/data/fonts/fonts.mk)
+
+# Overrides
+PRODUCT_BRAND := tiny
+PRODUCT_DEVICE := tiny
+PRODUCT_NAME := core_tiny
+
+$(call inherit-product, $(SRC_TARGET_DIR)/product/base.mk)
diff --git a/target/product/embedded.mk b/target/product/embedded.mk
index d370af9..b0a5396 100644
--- a/target/product/embedded.mk
+++ b/target/product/embedded.mk
@@ -20,6 +20,7 @@
 PRODUCT_PACKAGES += \
     adb \
     adbd \
+    atrace \
     bootanimation \
     debuggerd \
     dumpstate \
@@ -58,6 +59,7 @@
     libui \
     libutils \
     linker \
+    lmkd \
     logcat \
     logwrapper \
     mkshrc \
diff --git a/target/product/sdk.mk b/target/product/sdk.mk
index bc59782..4005e57 100644
--- a/target/product/sdk.mk
+++ b/target/product/sdk.mk
@@ -62,7 +62,8 @@
 	SmokeTest \
 	SmokeTestApp \
 	rild \
-	LegacyCamera
+	LegacyCamera \
+	Dialer
 
 # Define the host tools and libs that are parts of the SDK.
 -include sdk/build/product_sdk.mk
diff --git a/tools/droiddoc/templates-ds/jd_lists_unified.cs b/tools/droiddoc/templates-ds/jd_lists_unified.cs
new file mode 100644
index 0000000..417a5c1
--- /dev/null
+++ b/tools/droiddoc/templates-ds/jd_lists_unified.cs
@@ -0,0 +1 @@
+<?cs var:reference_tree ?>
diff --git a/tools/droiddoc/templates-pdk/jd_lists_unified.cs b/tools/droiddoc/templates-pdk/jd_lists_unified.cs
new file mode 100644
index 0000000..417a5c1
--- /dev/null
+++ b/tools/droiddoc/templates-pdk/jd_lists_unified.cs
@@ -0,0 +1 @@
+<?cs var:reference_tree ?>
diff --git a/tools/droiddoc/templates-sac/jd_lists_unified.cs b/tools/droiddoc/templates-sac/jd_lists_unified.cs
new file mode 100644
index 0000000..417a5c1
--- /dev/null
+++ b/tools/droiddoc/templates-sac/jd_lists_unified.cs
@@ -0,0 +1 @@
+<?cs var:reference_tree ?>
diff --git a/tools/droiddoc/templates-sdk/assets/css/default.css b/tools/droiddoc/templates-sdk/assets/css/default.css
index c4b81d2..69418df 100644
--- a/tools/droiddoc/templates-sdk/assets/css/default.css
+++ b/tools/droiddoc/templates-sdk/assets/css/default.css
@@ -428,6 +428,10 @@
   border-bottom:0;
   padding:0;
 }
+.content-header > div:first-child {
+  height:55px; /* set fixed height for the header div to ensure the
+                  next/prev links align with toc on training classes */
+}
 
 .content-footer {
   border-top: 1px solid #ccc;
@@ -524,6 +528,11 @@
     width:262px;
   }
 
+  .paging-links a.start-class-link {
+    width:100%;
+    text-align:right;
+  }
+
   /* list of classes on course landing page */
   ol.class-list {
     list-style:none;
@@ -1824,7 +1833,7 @@
 }
 
 #tb-wrapper {
-  margin:-27px 0 0 20px; /* negative top-margin to counter the content-header bottom margin */
+  margin:-29px 0 0 20px; /* negative top-margin to counter the content-header bottom margin */
 }
 
 #tb,
@@ -1897,6 +1906,10 @@
   font-size:inherit;
 }
 
+.sidebox > *:last-child {
+  margin-bottom:0;
+}
+
 #tb ol,
 #tb ul,
 #qv ul {
@@ -2259,12 +2272,16 @@
 
 
 /* nav tree */
-#side-nav, #devdoc-nav, #swapper,
+#side-nav, #swapper,
 #nav-tree, #tree-list {
   overflow:hidden;
   margin-left:0;
 }
 
+#devdoc-nav {
+  overflow:visible !important; /* To keep the "to top" button visible */
+}
+
 #nav-tree ul {
   list-style:none;
   padding:0;
@@ -2497,7 +2514,7 @@
 }
 
 /* --------------------------------------------------------------------------
-Styles for samples project trees and code browsing in resources tab 
+Styles for samples browser
 */
 
 #codesample-wrapper {
@@ -2543,6 +2560,30 @@
   display:inline-block;
 }
 
+/*
+Styles for displaying image or video resources in samples browser.
+Resources are marked as no-display if they exceed the size limit.
+*/
+div#codesample-resource img, div#codesample-resource video {
+  border: 1px solid #ececec;
+}
+
+div#codesample-resource.noDisplay div {
+  border: 1px solid #ececec;
+  width:120px;
+  margin-bottom:4px;
+  padding:20px;
+}
+
+div#codesample-resource .noDisplay-message:after {
+  font-style:italic;
+  font-size:12px;
+  content: 'This resource is not available for browsing. To view it, please download the project.';
+}
+
+/*
+Styles for project structure (treeview) page
+*/
 .structure-dir {
 background-image:url(../../assets/images/folder.png);
 background-repeat:no-repeat;
@@ -4791,25 +4832,32 @@
 
 .landing-banner,
 .landing-docs {
-  margin:20px 0 0;
+  margin:20px 0;
 }
-.landing-banner div:first-child,
-.landing-docs div:first-child,
-.landing-docs .col-12 {
+.landing-banner > div:first-child,
+.landing-docs > div:first-child,
+.landing-docs > .col-12 {
   margin-left:0;
   min-height:280px;
 }
-.landing-banner div:last-child,
-.landing-docs div:last-child,
-.landing-docs .col-12 {
+.landing-banner.short > div {
+  min-height:50px;
+}
+.landing-banner > div:last-child,
+.landing-docs > div:last-child,
+.landing-docs > .col-12 {
   margin-right:0;
 }
 
+.landing-banner > div > *:last-child {
+  margin-bottom:0;
+}
 .landing-banner h1 {
   margin-top:0;
 }
-.landing-docs {
-  clear:left;
+.landing-docs,
+.landing-banner {
+  clear:both;
   overflow:hidden;
 }
 .landing-docs h3 {
@@ -4839,6 +4887,32 @@
 
 
 
+.next-docs {
+  border-top:1px solid #ccc;
+  margin:40px 0 0;
+  padding:5px 0 0;
+  clear:left;
+  overflow:hidden;
+}
+.next-docs div:first-child {
+  margin-left:0;
+}
+.next-docs div:last-child {
+  margin-right:0;
+}
+
+.next-docs h2 {
+  font-size:14px;
+  line-height:21px;
+  color:#555;
+  text-transform:uppercase;
+  border-bottom:none;
+  margin:0 0 1em;
+  padding:5px 0 0;
+}
+
+
+
 /************* HOME/LANDING PAGE *****************/
 
 .slideshow-home {
diff --git a/tools/droiddoc/templates-sdk/assets/js/docs.js b/tools/droiddoc/templates-sdk/assets/js/docs.js
index 1996dac..6630bf9 100644
--- a/tools/droiddoc/templates-sdk/assets/js/docs.js
+++ b/tools/droiddoc/templates-sdk/assets/js/docs.js
@@ -23,7 +23,7 @@
 $(document).ready(function() {
 
   // load json file for JD doc search suggestions
-  $.getScript(toRoot + 'reference/jd_lists.js');
+  $.getScript(toRoot + 'jd_lists_unified.js');
   // load json file for Android API search suggestions
   $.getScript(toRoot + 'reference/lists.js');
   // load json files for Google services API suggestions
@@ -1539,6 +1539,13 @@
     $link.attr('href',toroot + match.link);
 }
 
+function set_item_values_jd(toroot, $li, match)
+{
+    var $link = $('a',$li);
+    $link.html(match.title);
+    $link.attr('href',toroot + match.url);
+}
+
 function new_suggestion($list) {
     var $li = $("<li class='jd-autocomplete'></li>");
     $list.append($li);
@@ -1615,6 +1622,9 @@
         $(".search_filtered_wrapper.docs li").remove();
 
         // determine google results to show
+        // NOTE: The order of the conditions below for the sugg.type MUST BE SPECIFIC:
+        // The order must match the reverse order that each section appears as a card in
+        // the suggestion UI... this may be only for the "develop" grouped items though.
         gDocsListLength = gDocsMatches.length < ROW_COUNT_DOCS ? gDocsMatches.length : ROW_COUNT_DOCS;
         for (i=0; i<gDocsListLength; i++) {
             var sugg = gDocsMatches[i];
@@ -1625,16 +1635,19 @@
             if (sugg.type == "distribute") {
                 $li = new_suggestion($(".suggest-card.distribute ul"));
             } else
+            if (sugg.type == "samples") {
+                $li = new_suggestion($(".suggest-card.develop .child-card.samples"));
+            } else
             if (sugg.type == "training") {
                 $li = new_suggestion($(".suggest-card.develop .child-card.training"));
             } else
-            if (sugg.type == "guide"||"google") {
+            if (sugg.type == "about"||"guide"||"tools"||"google") {
                 $li = new_suggestion($(".suggest-card.develop .child-card.guides"));
             } else {
               continue;
             }
 
-            set_item_values(toroot, $li, sugg);
+            set_item_values_jd(toroot, $li, sugg);
             set_item_selected($li, i == gSelectedIndex);
         }
 
@@ -1659,6 +1672,10 @@
           $(".child-card.training").prepend("<li class='header'>Training:</li>");
           $(".child-card.training li").appendTo(".suggest-card.develop ul");
         }
+        if ($(".child-card.samples li").length > 0) {
+          $(".child-card.samples").prepend("<li class='header'>Samples:</li>");
+          $(".child-card.samples li").appendTo(".suggest-card.develop ul");
+        }
 
         if ($(".suggest-card.develop li").length > 0) {
           $(".suggest-card.develop").show(300);
@@ -1681,6 +1698,7 @@
   */
 function search_changed(e, kd, toroot)
 {
+    var currentLang = getLangPref();
     var search = document.getElementById("search_autocomplete");
     var text = search.value.replace(/(^ +)|( +$)/g, '');
     // get the ul hosting the currently selected item
@@ -1794,8 +1812,8 @@
       }
     }
 
-    // if key-up event and not arrow down/up,
-    // read the search query and add suggestsions to gMatches
+    // if key-up event and not arrow down/up/left/right,
+    // read the search query and add suggestions to gMatches
     else if (!kd && (e.keyCode != 40)
                  && (e.keyCode != 38)
                  && (e.keyCode != 37)
@@ -1841,31 +1859,35 @@
 
 
 
-        // Search for JD docs
+        // Search for matching JD docs
         if (text.length >= 3) {
-          for (var i=0; i<JD_DATA.length; i++) {
-            // Regex to match only the beginning of a word
-            var textRegex = new RegExp("\\b" + text.toLowerCase(), "g");
+          // Regex to match only the beginning of a word
+          var textRegex = new RegExp("\\b" + text.toLowerCase(), "g");
+
+
+          // Search for Training classes
+          for (var i=0; i<TRAINING_RESOURCES.length; i++) {
             // current search comparison, with counters for tag and title,
             // used later to improve ranking
-            var s = JD_DATA[i];
+            var s = TRAINING_RESOURCES[i];
             s.matched_tag = 0;
             s.matched_title = 0;
             var matched = false;
 
             // Check if query matches any tags; work backwards toward 1 to assist ranking
-            for (var j = s.tags.length - 1; j >= 0; j--) {
+            for (var j = s.keywords.length - 1; j >= 0; j--) {
               // it matches a tag
-              if (s.tags[j].toLowerCase().match(textRegex)) {
+              if (s.keywords[j].toLowerCase().match(textRegex)) {
                 matched = true;
                 s.matched_tag = j + 1; // add 1 to index position
               }
             }
-            // Don't consider doc title for lessons (only for class landing pages)
-            // ...it is not a training lesson (or is but has matched a tag)
-            if (!(s.type == "training" && s.link.indexOf("index.html") == -1) || matched) {
+            // Don't consider doc title for lessons (only for class landing pages),
+            // unless the lesson has a tag that already matches
+            if ((s.lang == currentLang) &&
+                  (!(s.type == "training" && s.url.indexOf("index.html") == -1) || matched)) {
               // it matches the doc title
-              if (s.label.toLowerCase().match(textRegex)) {
+              if (s.title.toLowerCase().match(textRegex)) {
                 matched = true;
                 s.matched_title = 1;
               }
@@ -1875,6 +1897,231 @@
               matchedCountDocs++;
             }
           }
+
+
+          // Search for API Guides
+          for (var i=0; i<GUIDE_RESOURCES.length; i++) {
+            // current search comparison, with counters for tag and title,
+            // used later to improve ranking
+            var s = GUIDE_RESOURCES[i];
+            s.matched_tag = 0;
+            s.matched_title = 0;
+            var matched = false;
+
+            // Check if query matches any tags; work backwards toward 1 to assist ranking
+            for (var j = s.keywords.length - 1; j >= 0; j--) {
+              // it matches a tag
+              if (s.keywords[j].toLowerCase().match(textRegex)) {
+                matched = true;
+                s.matched_tag = j + 1; // add 1 to index position
+              }
+            }
+            // Check if query matches the doc title, but only for current language
+            if (s.lang == currentLang) {
+              // if query matches the doc title
+              if (s.title.toLowerCase().match(textRegex)) {
+                matched = true;
+                s.matched_title = 1;
+              }
+            }
+            if (matched) {
+              gDocsMatches[matchedCountDocs] = s;
+              matchedCountDocs++;
+            }
+          }
+
+
+          // Search for Tools Guides
+          for (var i=0; i<TOOLS_RESOURCES.length; i++) {
+            // current search comparison, with counters for tag and title,
+            // used later to improve ranking
+            var s = TOOLS_RESOURCES[i];
+            s.matched_tag = 0;
+            s.matched_title = 0;
+            var matched = false;
+
+            // Check if query matches any tags; work backwards toward 1 to assist ranking
+            for (var j = s.keywords.length - 1; j >= 0; j--) {
+              // it matches a tag
+              if (s.keywords[j].toLowerCase().match(textRegex)) {
+                matched = true;
+                s.matched_tag = j + 1; // add 1 to index position
+              }
+            }
+            // Check if query matches the doc title, but only for current language
+            if (s.lang == currentLang) {
+              // if query matches the doc title
+              if (s.title.toLowerCase().match(textRegex)) {
+                matched = true;
+                s.matched_title = 1;
+              }
+            }
+            if (matched) {
+              gDocsMatches[matchedCountDocs] = s;
+              matchedCountDocs++;
+            }
+          }
+
+
+          // Search for About docs
+          for (var i=0; i<ABOUT_RESOURCES.length; i++) {
+            // current search comparison, with counters for tag and title,
+            // used later to improve ranking
+            var s = ABOUT_RESOURCES[i];
+            s.matched_tag = 0;
+            s.matched_title = 0;
+            var matched = false;
+
+            // Check if query matches any tags; work backwards toward 1 to assist ranking
+            for (var j = s.keywords.length - 1; j >= 0; j--) {
+              // it matches a tag
+              if (s.keywords[j].toLowerCase().match(textRegex)) {
+                matched = true;
+                s.matched_tag = j + 1; // add 1 to index position
+              }
+            }
+            // Check if query matches the doc title, but only for current language
+            if (s.lang == currentLang) {
+              // if query matches the doc title
+              if (s.title.toLowerCase().match(textRegex)) {
+                matched = true;
+                s.matched_title = 1;
+              }
+            }
+            if (matched) {
+              gDocsMatches[matchedCountDocs] = s;
+              matchedCountDocs++;
+            }
+          }
+
+
+          // Search for Design guides
+          for (var i=0; i<DESIGN_RESOURCES.length; i++) {
+            // current search comparison, with counters for tag and title,
+            // used later to improve ranking
+            var s = DESIGN_RESOURCES[i];
+            s.matched_tag = 0;
+            s.matched_title = 0;
+            var matched = false;
+
+            // Check if query matches any tags; work backwards toward 1 to assist ranking
+            for (var j = s.keywords.length - 1; j >= 0; j--) {
+              // it matches a tag
+              if (s.keywords[j].toLowerCase().match(textRegex)) {
+                matched = true;
+                s.matched_tag = j + 1; // add 1 to index position
+              }
+            }
+            // Check if query matches the doc title, but only for current language
+            if (s.lang == currentLang) {
+              // if query matches the doc title
+              if (s.title.toLowerCase().match(textRegex)) {
+                matched = true;
+                s.matched_title = 1;
+              }
+            }
+            if (matched) {
+              gDocsMatches[matchedCountDocs] = s;
+              matchedCountDocs++;
+            }
+          }
+
+
+          // Search for Distribute guides
+          for (var i=0; i<DISTRIBUTE_RESOURCES.length; i++) {
+            // current search comparison, with counters for tag and title,
+            // used later to improve ranking
+            var s = DISTRIBUTE_RESOURCES[i];
+            s.matched_tag = 0;
+            s.matched_title = 0;
+            var matched = false;
+
+            // Check if query matches any tags; work backwards toward 1 to assist ranking
+            for (var j = s.keywords.length - 1; j >= 0; j--) {
+              // it matches a tag
+              if (s.keywords[j].toLowerCase().match(textRegex)) {
+                matched = true;
+                s.matched_tag = j + 1; // add 1 to index position
+              }
+            }
+            // Check if query matches the doc title, but only for current language
+            if (s.lang == currentLang) {
+              // if query matches the doc title
+              if (s.title.toLowerCase().match(textRegex)) {
+                matched = true;
+                s.matched_title = 1;
+              }
+            }
+            if (matched) {
+              gDocsMatches[matchedCountDocs] = s;
+              matchedCountDocs++;
+            }
+          }
+
+
+          // Search for Google guides
+          for (var i=0; i<GOOGLE_RESOURCES.length; i++) {
+            // current search comparison, with counters for tag and title,
+            // used later to improve ranking
+            var s = GOOGLE_RESOURCES[i];
+            s.matched_tag = 0;
+            s.matched_title = 0;
+            var matched = false;
+
+            // Check if query matches any tags; work backwards toward 1 to assist ranking
+            for (var j = s.keywords.length - 1; j >= 0; j--) {
+              // it matches a tag
+              if (s.keywords[j].toLowerCase().match(textRegex)) {
+                matched = true;
+                s.matched_tag = j + 1; // add 1 to index position
+              }
+            }
+            // Check if query matches the doc title, but only for current language
+            if (s.lang == currentLang) {
+              // if query matches the doc title
+              if (s.title.toLowerCase().match(textRegex)) {
+                matched = true;
+                s.matched_title = 1;
+              }
+            }
+            if (matched) {
+              gDocsMatches[matchedCountDocs] = s;
+              matchedCountDocs++;
+            }
+          }
+
+
+          // Search for Samples
+          for (var i=0; i<SAMPLES_RESOURCES.length; i++) {
+            // current search comparison, with counters for tag and title,
+            // used later to improve ranking
+            var s = SAMPLES_RESOURCES[i];
+            s.matched_tag = 0;
+            s.matched_title = 0;
+            var matched = false;
+            // Check if query matches any tags; work backwards toward 1 to assist ranking
+            for (var j = s.keywords.length - 1; j >= 0; j--) {
+              // it matches a tag
+              if (s.keywords[j].toLowerCase().match(textRegex)) {
+                matched = true;
+                s.matched_tag = j + 1; // add 1 to index position
+              }
+            }
+            // Check if query matches the doc title, but only for current language
+            if (s.lang == currentLang) {
+              // if query matches the doc title.t
+              if (s.title.toLowerCase().match(textRegex)) {
+                matched = true;
+                s.matched_title = 1;
+              }
+            }
+            if (matched) {
+              gDocsMatches[matchedCountDocs] = s;
+              matchedCountDocs++;
+            }
+          }
+
+          // Rank/sort all the matched pages
           rank_autocomplete_doc_results(text, gDocsMatches);
         }
 
diff --git a/tools/droiddoc/templates-sdk/components/masthead.cs b/tools/droiddoc/templates-sdk/components/masthead.cs
index f3eb401..47639bb 100644
--- a/tools/droiddoc/templates-sdk/components/masthead.cs
+++ b/tools/droiddoc/templates-sdk/components/masthead.cs
@@ -122,6 +122,8 @@
       </div>
       <div class="child-card training no-display">
       </div>
+      <div class="child-card samples no-display">
+      </div>
     </div>
     <div class="suggest-card design no-display">
       <ul class="search_filtered">
@@ -160,7 +162,7 @@
                           ja-lang="トレーニング"
                           es-lang="Capacitación"               
                           >Training</a></li>
-                        <li><a href="<?cs var:toroot ?>guide/components/index.html"
+                        <li><a href="<?cs var:toroot ?>guide/index.html"
                           zh-tw-lang="API 指南"
                           zh-cn-lang="API 指南"
                           ru-lang="Руководства по API"
@@ -231,7 +233,7 @@
                   ja-lang="トレーニング"
                   es-lang="Capacitación"               
                   >Training</a></li>
-                <li class="guide"><a href="<?cs var:toroot ?>guide/components/index.html"
+                <li class="guide"><a href="<?cs var:toroot ?>guide/index.html"
                   zh-tw-lang="API 指南"
                   zh-cn-lang="API 指南"
                   ru-lang="Руководства по API"
diff --git a/tools/droiddoc/templates-sdk/customizations.cs b/tools/droiddoc/templates-sdk/customizations.cs
index d54d371..ed57f1c 100644
--- a/tools/droiddoc/templates-sdk/customizations.cs
+++ b/tools/droiddoc/templates-sdk/customizations.cs
@@ -144,12 +144,8 @@
 <?cs
         include:"../../../../frameworks/base/docs/html/samples/samples_toc.cs" ?>
 
-
       </div>
-      <script type="text/javascript">
-       showSamplesRefTree();
 
-      </script>
     </div> <!-- end side-nav -->
     <script>
       $(document).ready(function() {
diff --git a/tools/droiddoc/templates-sdk/designpage.cs b/tools/droiddoc/templates-sdk/designpage.cs
index c714a74..2be179d 100644
--- a/tools/droiddoc/templates-sdk/designpage.cs
+++ b/tools/droiddoc/templates-sdk/designpage.cs
@@ -95,5 +95,16 @@
     var pageTracker = _gat._getTracker("UA-5831155-1");
     pageTracker._trackPageview();
     </script>
+
+<!-- Start of Tag -->
+<script type="text/javascript">
+var axel = Math.random() + "";
+var a = axel * 10000000000000;
+document.write('<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=' + a + '?" width="1" height="1" frameborder="0" style="display:none"></iframe>');
+</script>
+<noscript>
+<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=1?" width="1" height="1" frameborder="0" style="display:none"></iframe>
+</noscript>
+<!-- End of Tag -->
   </body>
 </html>
diff --git a/tools/droiddoc/templates-sdk/docpage.cs b/tools/droiddoc/templates-sdk/docpage.cs
index 6faac04..ea462c9 100644
--- a/tools/droiddoc/templates-sdk/docpage.cs
+++ b/tools/droiddoc/templates-sdk/docpage.cs
@@ -13,7 +13,7 @@
 
 <div <?cs if:fullpage
 ?>class="fullpage"<?cs elif:design||tools||about||sdk||distribute
-?>class="col-13" id="doc-col"<?cs else 
+?>class="col-13" id="doc-col"<?cs else
 ?>class="col-12" id="doc-col"<?cs /if ?> >
 
 <?cs if:(design||training||walkthru) && !page.trainingcourse && !page.article ?><?cs # header logic for docs that provide previous/next buttons ?>
@@ -33,7 +33,7 @@
             ru-lang="Предыдущий"
             ko-lang="이전"
             ja-lang="前へ"
-            es-lang="Anterior"               
+            es-lang="Anterior"
             >Previous</a>
         <a href="#" class="next-page-link hide"
             zh-tw-lang="下一堂課"
@@ -41,7 +41,7 @@
             ru-lang="Следующий"
             ko-lang="다음"
             ja-lang="次へ"
-            es-lang="Siguiente"               
+            es-lang="Siguiente"
             >Next</a>
         <a href="#" class="start-class-link hide"
             zh-tw-lang="開始上課"
@@ -49,7 +49,7 @@
             ru-lang="Начало работы"
             ko-lang="시작하기"
             ja-lang="開始する"
-            es-lang="Empezar"               
+            es-lang="Empezar"
             >Get started</a>
       </div>
     <?cs elif:!page.trainingcourse ?>
@@ -60,7 +60,7 @@
             ru-lang="Предыдущий"
             ko-lang="이전"
             ja-lang="前へ"
-            es-lang="Anterior"               
+            es-lang="Anterior"
             >Previous</a>
         <a href="#" class="next-page-link hide"
             zh-tw-lang="下一堂課"
@@ -68,17 +68,26 @@
             ru-lang="Следующий"
             ko-lang="다음"
             ja-lang="次へ"
-            es-lang="Siguiente"               
+            es-lang="Siguiente"
             >Next</a>
       </div>
     <?cs /if ?><?cs # end if training ?>
   </div>
   <?cs /if ?>
+<?cs elif:samplesProjectIndex ?>
+  <div id="api-info-block">
+  <div class="sum-details-links">
+  Overview
+  &#124; <a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/project.html">Project</a>
+  &#124; <a href="<?cs var:toroot ?>downloads/samples/<?cs var:projectDir ?>.zip">Download</a>
+  </div><!-- end sum-details-links -->
+  </div><!-- end breadcurmb block -->
+  <h1 itemprop="name"><?cs var:projectDir ?></h1>
 <?cs else ?>
   <?cs if:(!fullpage && !header.hide) ?>
     <?cs if:page.landing ?><?cs # header logic for docs that are landing pages ?>
       <div class="landing-banner">
-        <?cs if:page.landing.image ?><?cs # use two-column layout only if there's an image ?>
+        <?cs if:page.landing.image ?><?cs # use two-column layout only if there is an image ?>
         <div class="col-6">
           <img src="<?cs var:toroot ?><?cs var:page.landing.image ?>" alt="" />
         </div>
@@ -86,7 +95,7 @@
         <?cs /if ?>
           <h1 itemprop="name" style="margin-bottom:0;"><?cs var:page.title ?></h1>
           <p itemprop="description"><?cs var:page.landing.intro ?></p>
-          
+
           <p><a class="next-page-link topic-start-link"></a></p>
         <?cs if:page.landing.image ?>
         </div>
@@ -115,14 +124,14 @@
     <div class="jd-descr" itemprop="articleBody">
     <?cs call:tag_list(root.descr) ?>
     </div>
-      
-      <div class="content-footer <?cs 
+
+      <div class="content-footer <?cs
                     if:fullpage ?>wrap<?cs
-                    else ?>layout-content-row<?cs /if ?>" 
+                    else ?>layout-content-row<?cs /if ?>"
                     itemscope itemtype="http://schema.org/SiteNavigationElement">
-        <div class="layout-content-col <?cs 
-                    if:fullpage ?>col-16<?cs 
-                    elif:training||guide ?>col-8<?cs 
+        <div class="layout-content-col <?cs
+                    if:fullpage ?>col-16<?cs
+                    elif:training||guide ?>col-8<?cs
                     else ?>col-9<?cs /if ?>" style="padding-top:4px">
           <?cs if:!page.noplus ?><?cs if:fullpage ?><style>#___plusone_0 {float:right !important;}</style><?cs /if ?>
             <div class="g-plusone" data-size="medium"></div>
@@ -137,7 +146,7 @@
                 ru-lang="Предыдущий"
                 ko-lang="이전"
                 ja-lang="前へ"
-                es-lang="Anterior"               
+                es-lang="Anterior"
                 >Previous</a>
             <a href="#" class="next-page-link hide"
                 zh-tw-lang="下一堂課"
@@ -145,13 +154,21 @@
                 ru-lang="Следующий"
                 ko-lang="다음"
                 ja-lang="次へ"
-                es-lang="Siguiente"               
+                es-lang="Siguiente"
                 >Next</a>
+            <a href="#" class="start-class-link hide"
+                zh-tw-lang="開始上課"
+                zh-cn-lang="开始"
+                ru-lang="Начало работы"
+                ko-lang="시작하기"
+                ja-lang="開始する"
+                es-lang="Empezar"
+                >Get started</a>
           <?cs /if ?>
         </div>
         <?cs /if ?>
       </div>
-      
+
       <?cs # for training classes, provide a different kind of link when the next page is a different class ?>
       <?cs if:training && !page.article ?>
       <div class="layout-content-row content-footer next-class" style="display:none" itemscope itemtype="http://schema.org/SiteNavigationElement">
@@ -166,6 +183,16 @@
 
 <?cs include:"trailer.cs" ?>
 
+<!-- Start of Tag -->
+<script type="text/javascript">
+var axel = Math.random() + "";
+var a = axel * 10000000000000;
+document.write('<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=' + a + '?" width="1" height="1" frameborder="0" style="display:none"></iframe>');
+</script>
+<noscript>
+<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=1?" width="1" height="1" frameborder="0" style="display:none"></iframe>
+</noscript>
+<!-- End of Tag -->
 </body>
 </html>
 
diff --git a/tools/droiddoc/templates-sdk/head_tag.cs b/tools/droiddoc/templates-sdk/head_tag.cs
index 379829c..54de169 100644
--- a/tools/droiddoc/templates-sdk/head_tag.cs
+++ b/tools/droiddoc/templates-sdk/head_tag.cs
@@ -50,6 +50,7 @@
 /if ?>
 <script type="text/javascript">
   var toRoot = "<?cs var:toroot ?>";
+  var metaTags = [<?cs var:meta.tags ?>];
   var devsite = <?cs if:devsite ?>true<?cs else ?>false<?cs /if ?>;
 </script>
 <script src="<?cs var:toroot ?>assets/js/docs.js" type="text/javascript"></script>
diff --git a/tools/droiddoc/templates-sdk/jd_lists_unified.cs b/tools/droiddoc/templates-sdk/jd_lists_unified.cs
new file mode 100644
index 0000000..417a5c1
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/jd_lists_unified.cs
@@ -0,0 +1 @@
+<?cs var:reference_tree ?>
diff --git a/tools/droiddoc/templates-sdk/sample.cs b/tools/droiddoc/templates-sdk/sample.cs
index 3fed799..c6f28f8 100644
--- a/tools/droiddoc/templates-sdk/sample.cs
+++ b/tools/droiddoc/templates-sdk/sample.cs
@@ -7,7 +7,7 @@
 
 <div <?cs if:fullpage
 ?>class="fullpage"<?cs elif:design||tools||about||sdk||distribute
-?>class="col-13" id="doc-col"<?cs else 
+?>class="col-13" id="doc-col"<?cs else
 ?>class="col-12" id="doc-col"<?cs /if ?> >
 
 <!-- start breadcrumb block -->
@@ -17,7 +17,9 @@
   <!-- related links -->
   <a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/index.html">Overview</a>
   &#124; <a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/project.html">Project</a>
-  &#124; <a href="<?cs var:toroot ?>downloads/samples/<?cs var:projectDir ?>.zip">Download</a>
+  &#124; <a href="<?cs var:toroot ?>downloads/samples/<?cs var:projectDir ?>.zip"
+    onclick="_gaq.push(['_trackEvent', 'Samples', 'Download', <?cs var:projectDir ?>]);"
+    >Download</a>
 
 </div><!-- end sum-details-links -->
 
@@ -27,7 +29,7 @@
 
 <div id="pathCrumb">
 <?cs each:item = parentdirs ?>
-  <?cs if:pathCrumbLinks
+  <?cs if:LinkifyPathCrumb
     ?><a href="<?cs var:toroot ?><?cs var:item.Link ?>"><?cs var:item.Name ?></a> / 
   <?cs else
     ?><?cs var:item.Name ?> / <?cs /if ?>
@@ -50,18 +52,37 @@
 <?cs var:summary ?>
 
 <!-- begin file contents -->
-<div id="codesample-wrapper">
-<pre id="codesample-line-numbers" class="no-pretty-print hidden"></pre>
-<pre id="codesample-block"><?cs var:fileContents ?></pre>
-</div>
+
+<?cs # embed image/videos if below maxsize (show message otherwise), else display source code ?>
+<?cs if:resType == "img" ?>
+  <div id="codesample-resource"
+    <?cs if:noDisplay ?>
+      class="noDisplay"><div class="noDisplay-message"></div>
+    <?cs else ?>
+      ><img src="<?cs var:realFile ?>" title="<?cs var:page.title ?>">
+    <?cs /if ?>
+  </div>
+<?cs elif:resType == "video" ?>
+  <div id="codesample-resource"
+    <?cs if:noDisplay ?>
+      class="noDisplay"><div class="noDisplay-message"></div>
+    <?cs else ?>
+      ><video class="play-on-hover" controls style="border:1px solid #ececec;background-color:#f9f9f9;" poster="">
+        <source src="<?cs var:page.title ?>">
+      </video>
+    <?cs /if ?>
+  </div>
+<?cs else ?>
+  <div id="codesample-wrapper">
+    <pre id="codesample-line-numbers" class="no-pretty-print hidden"></pre>
+    <pre id="codesample-block"><?cs var:fileContents ?></pre>
+  </div>
+  <script type="text/javascript">
+  initCodeLineNumbers();
+  </script>
+<?cs /if ?>
 
 <!-- end file contents -->
-<script type="text/javascript">
-  initCodeLineNumbers();
-</script>
-
-
-
 
 <?cs else ?><?cs
   # else, this means it's offline docs,
@@ -69,6 +90,49 @@
 
 <?cs /if ?><?cs # end if/else online docs ?>
 
+      <div class="content-footer <?cs
+                    if:fullpage ?>wrap<?cs
+                    else ?>layout-content-row<?cs /if ?>"
+                    itemscope itemtype="http://schema.org/SiteNavigationElement">
+        <div class="layout-content-col <?cs
+                    if:fullpage ?>col-16<?cs
+                    elif:training||guide ?>col-8<?cs
+                    else ?>col-9<?cs /if ?>" style="padding-top:4px">
+          <?cs if:!page.noplus ?><?cs if:fullpage ?><style>#___plusone_0 {float:right !important;}</style><?cs /if ?>
+            <div class="g-plusone" data-size="medium"></div>
+          <?cs /if ?>
+        </div>
+        <?cs if:!fullscreen ?>
+        <div class="paging-links layout-content-col col-4">
+          <?cs if:(design||training||walkthru) && !page.landing && !page.trainingcourse && !footer.hide ?>
+            <a href="#" class="prev-page-link hide"
+                zh-tw-lang="上一堂課"
+                zh-cn-lang="上一课"
+                ru-lang="Предыдущий"
+                ko-lang="이전"
+                ja-lang="前へ"
+                es-lang="Anterior"
+                >Previous</a>
+            <a href="#" class="next-page-link hide"
+                zh-tw-lang="下一堂課"
+                zh-cn-lang="下一课"
+                ru-lang="Следующий"
+                ko-lang="다음"
+                ja-lang="次へ"
+                es-lang="Siguiente"
+                >Next</a>
+          <?cs /if ?>
+        </div>
+        <?cs /if ?>
+      </div>
+
+      <?cs # for training classes, provide a different kind of link when the next page is a different class ?>
+      <?cs if:training && !page.article ?>
+      <div class="layout-content-row content-footer next-class" style="display:none" itemscope itemtype="http://schema.org/SiteNavigationElement">
+          <a href="#" class="next-class-link hide">Next class: </a>
+      </div>
+      <?cs /if ?>
+
   </div> <!-- end jd-content -->
 
 <?cs include:"footer.cs" ?>
diff --git a/tools/droiddoc/templates-sdk/sampleindex.cs b/tools/droiddoc/templates-sdk/sampleindex.cs
index 8db15c4..98767b1 100644
--- a/tools/droiddoc/templates-sdk/sampleindex.cs
+++ b/tools/droiddoc/templates-sdk/sampleindex.cs
@@ -20,7 +20,9 @@
 &#124; Project<?cs else ?>Overview
 &#124; <a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/project.html">Project</a>
 <?cs /if ?>
-&#124; <a href="<?cs var:toroot ?>downloads/samples/<?cs var:projectDir ?>.zip">Download</a>
+&#124; <a href="<?cs var:toroot ?>downloads/samples/<?cs var:projectDir ?>.zip"
+    onclick="_gaq.push(['_trackEvent', 'Samples', 'Download', <?cs var:projectDir ?>]);"
+    >Download</a>
 
 </div><!-- end sum-details-links -->
 
@@ -78,6 +80,48 @@
           so don't show src links (we dont have the pages!) ?>
 
 <?cs /if ?><?cs # end if/else online docs ?>
+      <div class="content-footer <?cs
+                    if:fullpage ?>wrap<?cs
+                    else ?>layout-content-row<?cs /if ?>"
+                    itemscope itemtype="http://schema.org/SiteNavigationElement">
+        <div class="layout-content-col <?cs
+                    if:fullpage ?>col-16<?cs
+                    elif:training||guide ?>col-8<?cs
+                    else ?>col-9<?cs /if ?>" style="padding-top:4px">
+          <?cs if:!page.noplus ?><?cs if:fullpage ?><style>#___plusone_0 {float:right !important;}</style><?cs /if ?>
+            <div class="g-plusone" data-size="medium"></div>
+          <?cs /if ?>
+        </div>
+        <?cs if:!fullscreen ?>
+        <div class="paging-links layout-content-col col-4">
+          <?cs if:(design||training||walkthru) && !page.landing && !page.trainingcourse && !footer.hide ?>
+            <a href="#" class="prev-page-link hide"
+                zh-tw-lang="上一堂課"
+                zh-cn-lang="上一课"
+                ru-lang="Предыдущий"
+                ko-lang="이전"
+                ja-lang="前へ"
+                es-lang="Anterior"
+                >Previous</a>
+            <a href="#" class="next-page-link hide"
+                zh-tw-lang="下一堂課"
+                zh-cn-lang="下一课"
+                ru-lang="Следующий"
+                ko-lang="다음"
+                ja-lang="次へ"
+                es-lang="Siguiente"
+                >Next</a>
+          <?cs /if ?>
+        </div>
+        <?cs /if ?>
+      </div>
+
+      <?cs # for training classes, provide a different kind of link when the next page is a different class ?>
+      <?cs if:training && !page.article ?>
+      <div class="layout-content-row content-footer next-class" style="display:none" itemscope itemtype="http://schema.org/SiteNavigationElement">
+          <a href="#" class="next-class-link hide">Next class: </a>
+      </div>
+      <?cs /if ?>
 
   </div> <!-- end jd-content -->
 
diff --git a/tools/droiddoc/templates-sdk/sdkpage.cs b/tools/droiddoc/templates-sdk/sdkpage.cs
index ecc26f5..d98146a 100644
--- a/tools/droiddoc/templates-sdk/sdkpage.cs
+++ b/tools/droiddoc/templates-sdk/sdkpage.cs
@@ -83,7 +83,7 @@
       <th>MD5 Checksum</th>
   </tr>
   <tr>
-    <td rowspan="2" style="white-space:nowrap">Windows 32-bit</td>
+    <td>Windows 32-bit</td>
     <td>
   <a onClick="return onDownload(this)"
      href="http://dl.google.com/android/ndk/<?cs var:ndk.win32_download ?>"><?cs var:ndk.win32_download ?></a>
@@ -91,33 +91,33 @@
     <td><?cs var:ndk.win32_bytes ?></td>
     <td><?cs var:ndk.win32_checksum ?></td>
   </tr>
-  <tr>
-    <td>
+ <!-- <tr>
+   <td>
   <a onClick="return onDownload(this)"
      href="http://dl.google.com/android/ndk/<?cs var:ndk.win32.legacy_download ?>"><?cs var:ndk.win32.legacy_download ?></a>
     </td>
     <td><?cs var:ndk.win32.legacy_bytes ?></td>
     <td><?cs var:ndk.win32.legacy_checksum ?></td>
-  </tr>
+  </tr> -->
   <tr>
-    <td rowspan="2" style="white-space:nowrap">Windows 64-bit</td>
+    <td>Windows 64-bit</td>
     <td>
   <a onClick="return onDownload(this)"
      href="http://dl.google.com/android/ndk/<?cs var:ndk.win64_download ?>"><?cs var:ndk.win64_download ?></a>
     </td>
     <td><?cs var:ndk.win64_bytes ?></td>
     <td><?cs var:ndk.win64_checksum ?></td>
-  </tr>
-  <tr>
+  </tr> 
+ <!--  <tr>
     <td>
   <a onClick="return onDownload(this)"
      href="http://dl.google.com/android/ndk/<?cs var:ndk.win64.legacy_download ?>"><?cs var:ndk.win64.legacy_download ?></a>
     </td>
     <td><?cs var:ndk.win64.legacy_bytes ?></td>
     <td><?cs var:ndk.win64.legacy_checksum ?></td>
-  </tr>
+  </tr> -->
   <tr>
-    <td rowspan="2" style="white-space:nowrap">Mac OS X 32-bit</td>
+    <td>Mac OS X 32-bit</td>
     <td>
   <a onClick="return onDownload(this)"
      href="http://dl.google.com/android/ndk/<?cs var:ndk.mac32_download ?>"><?cs var:ndk.mac32_download ?></a>
@@ -125,16 +125,15 @@
     <td><?cs var:ndk.mac32_bytes ?></td>
     <td><?cs var:ndk.mac32_checksum ?></td>
   </tr>
-  <tr>
+ <!--  <tr>
     <td>
   <a onClick="return onDownload(this)"
      href="http://dl.google.com/android/ndk/<?cs var:ndk.mac32.legacy_download ?>"><?cs var:ndk.mac32.legacy_download ?></a>
     </td>
     <td><?cs var:ndk.mac32.legacy_bytes ?></td>
     <td><?cs var:ndk.mac32.legacy_checksum ?></td>
-  </tr>
-  <tr>
-    <td rowspan="2"  style="white-space:nowrap">Mac OS X 64-bit</td>
+  </tr> -->
+    <td>Mac OS X 64-bit</td>
     <td>
   <a onClick="return onDownload(this)"
      href="http://dl.google.com/android/ndk/<?cs var:ndk.mac64_download ?>"><?cs var:ndk.mac64_download ?></a>
@@ -142,17 +141,16 @@
     <td><?cs var:ndk.mac64_bytes ?></td>
     <td><?cs var:ndk.mac64_checksum ?></td>
   </tr>
-  <tr>
+ <!--  <tr>
     <td>
   <a onClick="return onDownload(this)"
      href="http://dl.google.com/android/ndk/<?cs var:ndk.mac64.legacy_download ?>"><?cs var:ndk.mac64.legacy_download ?></a>
     </td>
     <td><?cs var:ndk.mac64.legacy_bytes ?></td>
     <td><?cs var:ndk.mac64.legacy_checksum ?></td>
-  </tr>
-
+  </tr> -->
   <tr>
-    <td rowspan="2" style="white-space:nowrap">Linux 32-bit (x86)</td>
+    <td>Linux 32-bit (x86)</td>
     <td>
   <a onClick="return onDownload(this)"
      href="http://dl.google.com/android/ndk/<?cs var:ndk.linux32_download ?>"><?cs var:ndk.linux32_download ?></a>
@@ -160,16 +158,16 @@
     <td><?cs var:ndk.linux32_bytes ?></td>
     <td><?cs var:ndk.linux32_checksum ?></td>
   </tr>
-  <tr>
+ <!--  <tr>
     <td>
   <a onClick="return onDownload(this)"
      href="http://dl.google.com/android/ndk/<?cs var:ndk.linux32.legacy_download ?>"><?cs var:ndk.linux32.legacy_download ?></a>
     </td>
     <td><?cs var:ndk.linux32.legacy_bytes ?></td>
     <td><?cs var:ndk.linux32.legacy_checksum ?></td>
-  </tr>
+  </tr> -->
   <tr>
-    <td rowspan="2" style="white-space:nowrap">Linux 64-bit (x86)</td>
+    <td>Linux 64-bit (x86)</td>
     <td>
   <a onClick="return onDownload(this)"
      href="http://dl.google.com/android/ndk/<?cs var:ndk.linux64_download ?>"><?cs var:ndk.linux64_download ?></a>
@@ -177,13 +175,28 @@
     <td><?cs var:ndk.linux64_bytes ?></td>
     <td><?cs var:ndk.linux64_checksum ?></td>
   </tr>
-  <tr>
+  <!--  <tr>
     <td>
   <a onClick="return onDownload(this)"
      href="http://dl.google.com/android/ndk/<?cs var:ndk.linux64.legacy_download ?>"><?cs var:ndk.linux64.legacy_download ?></a>
     </td>
     <td><?cs var:ndk.linux64.legacy_bytes ?></td>
     <td><?cs var:ndk.linux64.legacy_checksum ?></td>
+  </tr> -->
+    <tr>
+      <th>Additional Download</th>
+      <th>Package</th>
+      <th style="white-space:nowrap">Size (Bytes)</th>
+      <th>MD5 Checksum</th>
+  </tr>
+  <tr>
+    <td>STL debug info</td>
+    <td>
+  <a onClick="return onDownload(this)"
+     href="http://dl.google.com/android/ndk/<?cs var:ndk.debug_info_download ?>"><?cs var:ndk.debug_info_download ?></a>
+    </td>
+    <td><?cs var:ndk.debug_info_bytes ?></td>
+    <td><?cs var:ndk.debug_info_checksum ?></td>
   </tr>
   </table>
   
@@ -491,6 +504,7 @@
       $("#sdk-terms-form,.sdk-terms-intro").fadeOut('slow');
       $("#next-steps").fadeIn('slow');
       $("h1#tos-header").text('Get Ready to Code!');
+      _gaq.push(['_trackEvent', 'SDK', 'ADT and Tools', $("#downloadForRealz").html()]);
       return true;
     } else {
       $("label#agreeLabel,#bitpicker input").parent().stop().animate({color: "#258AAF"}, 200,
@@ -560,6 +574,16 @@
 
 <?cs include:"trailer.cs" ?>
 
+<!-- Start of Tag -->
+<script type="text/javascript">
+var axel = Math.random() + "";
+var a = axel * 10000000000000;
+document.write('<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=' + a + '?" width="1" height="1" frameborder="0" style="display:none"></iframe>');
+</script>
+<noscript>
+<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=1?" width="1" height="1" frameborder="0" style="display:none"></iframe>
+</noscript>
+<!-- End of Tag -->
 </body>
 </html>
 
diff --git a/tools/releasetools/edify_generator.py b/tools/releasetools/edify_generator.py
index 189672c..426b713 100644
--- a/tools/releasetools/edify_generator.py
+++ b/tools/releasetools/edify_generator.py
@@ -188,6 +188,15 @@
     """Moves a file from one location to another."""
     if self.info.get("update_rename_support", False):
       self.script.append('rename("%s", "%s");' % (srcfile, tgtfile))
+    else:
+      raise ValueError("Rename not supported by update binary")
+
+  def SkipNextActionIfTargetExists(self, tgtfile, tgtsha1):
+    """Prepend an action with an apply_patch_check in order to
+       skip the action if the file exists.  Used when a patch
+       is later renamed."""
+    cmd = ('sha1_check(read_file("%s"), %s) || ' % (tgtfile, tgtsha1))
+    self.script.append(self._WordWrap(cmd))
 
   def ApplyPatch(self, srcfile, tgtfile, tgtsize, tgtsha1, *patchpairs):
     """Apply binary patches (in *patchpairs) to the given srcfile to
diff --git a/tools/releasetools/ota_from_target_files b/tools/releasetools/ota_from_target_files
index b7e6613..8d3f6ce 100755
--- a/tools/releasetools/ota_from_target_files
+++ b/tools/releasetools/ota_from_target_files
@@ -52,6 +52,11 @@
   -a  (--aslr_mode)  <on|off>
       Specify whether to turn on ASLR for the package (on by default).
 
+  -2  (--two_step)
+      Generate a 'two-step' OTA package, where recovery is updated
+      first, so that any changes made to the system partition are done
+      using the new recovery (new kernel, etc.).
+
 """
 
 import sys
@@ -88,6 +93,7 @@
 OPTIONS.extra_script = None
 OPTIONS.aslr_mode = True
 OPTIONS.worker_threads = 3
+OPTIONS.two_step = False
 OPTIONS.no_signing = False
 
 def MostPopularKey(d, default):
@@ -430,6 +436,46 @@
 
   AppendAssertions(script, OPTIONS.info_dict)
   device_specific.FullOTA_Assertions()
+
+  # Two-step package strategy (in chronological order, which is *not*
+  # the order in which the generated script has things):
+  #
+  # if stage is not "2/3" or "3/3":
+  #    write recovery image to boot partition
+  #    set stage to "2/3"
+  #    reboot to boot partition and restart recovery
+  # else if stage is "2/3":
+  #    write recovery image to recovery partition
+  #    set stage to "3/3"
+  #    reboot to recovery partition and restart recovery
+  # else:
+  #    (stage must be "3/3")
+  #    set stage to ""
+  #    do normal full package installation:
+  #       wipe and install system, boot image, etc.
+  #       set up system to update recovery partition on first boot
+  #    complete script normally (allow recovery to mark itself finished and reboot)
+
+  recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
+                                         OPTIONS.input_tmp, "RECOVERY")
+  if OPTIONS.two_step:
+    if not OPTIONS.info_dict.get("multistage_support", None):
+      assert False, "two-step packages not supported by this build"
+    fs = OPTIONS.info_dict["fstab"]["/misc"]
+    assert fs.fs_type.upper() == "EMMC", \
+        "two-step packages only supported on devices with EMMC /misc partitions"
+    bcb_dev = {"bcb_dev": fs.device}
+    common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
+    script.AppendExtra("""
+if get_stage("%(bcb_dev)s", "stage") == "2/3" then
+""" % bcb_dev)
+    script.WriteRawImage("/recovery", "recovery.img")
+    script.AppendExtra("""
+set_stage("%(bcb_dev)s", "3/3");
+reboot_now("%(bcb_dev)s", "recovery");
+else if get_stage("%(bcb_dev)s", "stage") == "3/3" then
+""" % bcb_dev)
+
   device_specific.FullOTA_InstallBegin()
 
   script.ShowProgress(0.5, 0)
@@ -450,8 +496,6 @@
 
   boot_img = common.GetBootableImage("boot.img", "boot.img",
                                      OPTIONS.input_tmp, "BOOT")
-  recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
-                                         OPTIONS.input_tmp, "RECOVERY")
   MakeRecoveryPatch(OPTIONS.input_tmp, output_zip, recovery_img, boot_img)
 
   Item.GetMetadata(input_zip)
@@ -471,6 +515,19 @@
     script.AppendExtra(OPTIONS.extra_script)
 
   script.UnmountAll()
+
+  if OPTIONS.two_step:
+    script.AppendExtra("""
+set_stage("%(bcb_dev)s", "");
+""" % bcb_dev)
+    script.AppendExtra("else\n")
+    script.WriteRawImage("/boot", "recovery.img")
+    script.AppendExtra("""
+set_stage("%(bcb_dev)s", "2/3");
+reboot_now("%(bcb_dev)s", "");
+endif;
+endif;
+""" % bcb_dev)
   script.AddToZip(input_zip, output_zip)
   WriteMetadata(metadata, output_zip)
 
@@ -505,6 +562,16 @@
   except KeyError:
     raise common.ExternalError("couldn't find %s in build.prop" % (property,))
 
+def AddToKnownPaths(filename, known_paths):
+  if filename[-1] == "/":
+    return
+  dirs = filename.split("/")[:-1]
+  while len(dirs) > 0:
+    path = "/".join(dirs)
+    if path in known_paths:
+      break;
+    known_paths.add(path)
+    dirs.pop()
 
 def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
   source_version = OPTIONS.source_info_dict["recovery_api_version"]
@@ -541,14 +608,16 @@
   patch_list = []
   diffs = []
   renames = {}
+  known_paths = set()
   largest_source_size = 0
 
   matching_file_cache = {}
-  for fn in source_data.keys():
-    sf = source_data[fn]
+  for fn, sf in source_data.items():
     assert fn == sf.name
     matching_file_cache["path:" + fn] = sf
-    # Only allow eligability for filename/sha matching
+    if fn in target_data.keys():
+      AddToKnownPaths(fn, known_paths)
+    # Only allow eligibility for filename/sha matching
     # if there isn't a perfect path match.
     if target_data.get(sf.name) is None:
       matching_file_cache["file:" + fn.split("/")[-1]] = sf
@@ -569,6 +638,8 @@
       print "send", fn, "verbatim"
       tf.AddToZip(output_zip)
       verbatim_targets.append((fn, tf.size))
+      if fn in target_data.keys():
+        AddToKnownPaths(fn, known_paths)
     elif tf.sha1 != sf.sha1:
       # File is different; consider sending as a patch
       diffs.append(common.Difference(tf, sf))
@@ -580,13 +651,20 @@
 
   for diff in diffs:
     tf, sf, d = diff.GetPatch()
-    if d is None or len(d) > tf.size * OPTIONS.patch_threshold:
+    path = "/".join(tf.name.split("/")[:-1])
+    if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
+        path not in known_paths:
       # patch is almost as big as the file; don't bother patching
+      # or a patch + rename cannot take place due to the target 
+      # directory not existing
       tf.AddToZip(output_zip)
       verbatim_targets.append((tf.name, tf.size))
+      if sf.name in renames:
+        del renames[sf.name]
+      AddToKnownPaths(tf.name, known_paths)
     else:
       common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
-      patch_list.append((sf.name, tf, sf, tf.size, common.sha1(d).hexdigest()))
+      patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
       largest_source_size = max(largest_source_size, sf.size)
 
   source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
@@ -602,7 +680,8 @@
       OPTIONS.source_info_dict)
   target_boot = common.GetBootableImage(
       "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
-  updating_boot = (source_boot.data != target_boot.data)
+  updating_boot = (not OPTIONS.two_step and
+                   (source_boot.data != target_boot.data))
 
   source_recovery = common.GetBootableImage(
       "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
@@ -620,18 +699,60 @@
   AppendAssertions(script, OPTIONS.target_info_dict)
   device_specific.IncrementalOTA_Assertions()
 
+  # Two-step incremental package strategy (in chronological order,
+  # which is *not* the order in which the generated script has
+  # things):
+  #
+  # if stage is not "2/3" or "3/3":
+  #    do verification on current system
+  #    write recovery image to boot partition
+  #    set stage to "2/3"
+  #    reboot to boot partition and restart recovery
+  # else if stage is "2/3":
+  #    write recovery image to recovery partition
+  #    set stage to "3/3"
+  #    reboot to recovery partition and restart recovery
+  # else:
+  #    (stage must be "3/3")
+  #    perform update:
+  #       patch system files, etc.
+  #       force full install of new boot image
+  #       set up system to update recovery partition on first boot
+  #    complete script normally (allow recovery to mark itself finished and reboot)
+
+  if OPTIONS.two_step:
+    if not OPTIONS.info_dict.get("multistage_support", None):
+      assert False, "two-step packages not supported by this build"
+    fs = OPTIONS.info_dict["fstab"]["/misc"]
+    assert fs.fs_type.upper() == "EMMC", \
+        "two-step packages only supported on devices with EMMC /misc partitions"
+    bcb_dev = {"bcb_dev": fs.device}
+    common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
+    script.AppendExtra("""
+if get_stage("%(bcb_dev)s", "stage") == "2/3" then
+""" % bcb_dev)
+    script.AppendExtra("sleep(20);\n");
+    script.WriteRawImage("/recovery", "recovery.img")
+    script.AppendExtra("""
+set_stage("%(bcb_dev)s", "3/3");
+reboot_now("%(bcb_dev)s", "recovery");
+else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
+""" % bcb_dev)
+
   script.Print("Verifying current system...")
 
   device_specific.IncrementalOTA_VerifyBegin()
 
   script.ShowProgress(0.1, 0)
-  total_verify_size = float(sum([i[2].size for i in patch_list]) + 1)
+  total_verify_size = float(sum([i[1].size for i in patch_list]) + 1)
   if updating_boot:
     total_verify_size += source_boot.size
   so_far = 0
 
-  for fn, tf, sf, size, patch_sha in patch_list:
-    script.PatchCheck("/"+fn, tf.sha1, sf.sha1)
+  for tf, sf, size, patch_sha in patch_list:
+    if tf.name != sf.name:
+      script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
+    script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
     so_far += sf.size
     script.SetProgress(so_far / total_verify_size)
 
@@ -657,10 +778,23 @@
 
   device_specific.IncrementalOTA_VerifyEnd()
 
+  if OPTIONS.two_step:
+    script.WriteRawImage("/boot", "recovery.img")
+    script.AppendExtra("""
+set_stage("%(bcb_dev)s", "2/3");
+reboot_now("%(bcb_dev)s", "");
+else
+""" % bcb_dev)
+
   script.Comment("---- start making changes here ----")
 
   device_specific.IncrementalOTA_InstallBegin()
 
+  if OPTIONS.two_step:
+    common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
+    script.WriteRawImage("/boot", "boot.img")
+    print "writing full boot image (forced by two-step mode)"
+
   if OPTIONS.wipe_user_data:
     script.Print("Erasing user data...")
     script.FormatPartition("/data")
@@ -681,31 +815,34 @@
   script.Print("Patching system files...")
   deferred_patch_list = []
   for item in patch_list:
-    fn, tf, sf, size, _ = item
+    tf, sf, size, _ = item
     if tf.name == "system/build.prop":
       deferred_patch_list.append(item)
       continue
-    script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
+    if (sf.name != tf.name):
+      script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
+    script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
     so_far += tf.size
     script.SetProgress(so_far / total_patch_size)
 
-  if updating_boot:
-    # Produce the boot image by applying a patch to the current
-    # contents of the boot partition, and write it back to the
-    # partition.
-    script.Print("Patching boot image...")
-    script.ApplyPatch("%s:%s:%d:%s:%d:%s"
-                      % (boot_type, boot_device,
-                         source_boot.size, source_boot.sha1,
-                         target_boot.size, target_boot.sha1),
-                      "-",
-                      target_boot.size, target_boot.sha1,
-                      source_boot.sha1, "patch/boot.img.p")
-    so_far += target_boot.size
-    script.SetProgress(so_far / total_patch_size)
-    print "boot image changed; including."
-  else:
-    print "boot image unchanged; skipping."
+  if not OPTIONS.two_step:
+    if updating_boot:
+      # Produce the boot image by applying a patch to the current
+      # contents of the boot partition, and write it back to the
+      # partition.
+      script.Print("Patching boot image...")
+      script.ApplyPatch("%s:%s:%d:%s:%d:%s"
+                        % (boot_type, boot_device,
+                           source_boot.size, source_boot.sha1,
+                           target_boot.size, target_boot.sha1),
+                        "-",
+                        target_boot.size, target_boot.sha1,
+                        source_boot.sha1, "patch/boot.img.p")
+      so_far += target_boot.size
+      script.SetProgress(so_far / total_patch_size)
+      print "boot image changed; including."
+    else:
+      print "boot image unchanged; skipping."
 
   if updating_recovery:
     # Recovery is generated as a patch using both the boot image
@@ -793,10 +930,17 @@
   # get set the OTA package again to retry.
   script.Print("Patching remaining system files...")
   for item in deferred_patch_list:
-    fn, tf, sf, size, _ = item
-    script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
+    tf, sf, size, _ = item
+    script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
   script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None)
 
+  if OPTIONS.two_step:
+    script.AppendExtra("""
+set_stage("%(bcb_dev)s", "");
+endif;
+endif;
+""" % bcb_dev)
+
   script.AddToZip(target_zip, output_zip)
   WriteMetadata(metadata, output_zip)
 
@@ -823,6 +967,8 @@
         OPTIONS.aslr_mode = False
     elif o in ("--worker_threads"):
       OPTIONS.worker_threads = int(a)
+    elif o in ("-2", "--two_step"):
+      OPTIONS.two_step = True
     elif o in ("--no_signing"):
       OPTIONS.no_signing = True
     else:
@@ -830,7 +976,7 @@
     return True
 
   args = common.ParseOptions(argv, __doc__,
-                             extra_opts="b:k:i:d:wne:a:",
+                             extra_opts="b:k:i:d:wne:a:2",
                              extra_long_opts=["board_config=",
                                               "package_key=",
                                               "incremental_from=",
@@ -839,6 +985,7 @@
                                               "extra_script=",
                                               "worker_threads=",
                                               "aslr_mode=",
+                                              "two_step",
                                               "no_signing",
                                               ],
                              extra_option_handler=option_handler)