am 24c1d149: am a01fa4f8: Merge "LOCAL_NATIVE_COVERAGE should imply -O0."

* commit '24c1d149678dcd03f679bfa0fc29386cee779935':
  LOCAL_NATIVE_COVERAGE should imply -O0.
diff --git a/.gitignore b/.gitignore
index 0d20b64..c9b568f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 *.pyc
+*.swp
diff --git a/CleanSpec.mk b/CleanSpec.mk
index b3239d7..07b3ece 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -200,6 +200,12 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/SprintDM.apk)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/omadm)
 
+# GCC 4.8
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/lib/*.o)
+
 # KLP I mean KitKat now API 19.
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/*)
@@ -211,11 +217,34 @@
 # 4.4.2
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
 
+# "L" and beyond.
+# Make libart the default runtime
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
+
 # Rename persist.sys.dalvik.vm.lib to allow new default
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
 
+# KKWT development
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/APPS/*)
+
+# L development
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/APPS/*)
+
+# L development
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/APPS/*)
+
 # Add ro.product.cpu.abilist{32,64} to build.prop.
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
+
+# Unset TARGET_PREFER_32_BIT_APPS for 64 bit targets.
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
 
 # Adding dalvik.vm.dex2oat-flags to eng builds
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
@@ -236,6 +265,14 @@
 # Switching to 32-bit-by-default host multilib build
 $(call add-clean-step, rm -rf $(HOST_OUT_INTERMEDIATES))
 
+# KKWT has become API 20
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/APPS/*)
+
+# ims-common.jar added to BOOTCLASSPATH
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/ETC/init.environ.rc_intermediates)
+
 # Change ro.zygote for core_64_bit.mk from zygote32_64 to zygote64_32
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/default.prop)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/default.prop)
@@ -245,6 +282,8 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/default.prop)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/default.prop)
 
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system)
+
 # Switch host builds to Clang by default
 $(call add-clean-step, rm -rf $(OUT_DIR)/host)
 
@@ -253,6 +292,16 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/default.prop)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/default.prop)
 
+# API 21?
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/APPS/*)
+
+# API 21!
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/APPS/*)
+
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/core/Makefile b/core/Makefile
index 6fcd394..cd65caf 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -22,7 +22,7 @@
 # src:dest pair is the first one to match the same dest"
 #$(1): the src:dest pair
 define check-product-copy-files
-$(if $(filter %.apk, $(1)),$(error \
+$(if $(filter %.apk, $(call word-colon, 2, $(1))),$(error \
     Prebuilt apk found in PRODUCT_COPY_FILES: $(1), use BUILD_PREBUILT instead!))
 endef
 # filter out the duplicate <source file>:<dest file> pairs.
@@ -109,7 +109,7 @@
 build_desc := $(TARGET_PRODUCT)-$(TARGET_BUILD_VARIANT) $(PLATFORM_VERSION) $(BUILD_ID) $(BUILD_NUMBER) $(BUILD_VERSION_TAGS)
 $(INSTALLED_BUILD_PROP_TARGET): PRIVATE_BUILD_DESC := $(build_desc)
 
-# The string used to uniquely identify this build;  used by the OTA server.
+# The string used to uniquely identify the combined build and product; used by the OTA server.
 ifeq (,$(strip $(BUILD_FINGERPRINT)))
   ifneq ($(filter eng.%,$(BUILD_NUMBER)),)
     # Trim down BUILD_FINGERPRINT: the default BUILD_NUMBER makes it easily exceed
@@ -124,6 +124,15 @@
   $(error BUILD_FINGERPRINT cannot contain spaces: "$(BUILD_FINGERPRINT)")
 endif
 
+# The string used to uniquely identify the system build; used by the OTA server.
+# This purposefully excludes any product-specific variables.
+ifeq (,$(strip $(BUILD_THUMBPRINT)))
+  BUILD_THUMBPRINT := $(PLATFORM_VERSION)/$(BUILD_ID)/$(BUILD_NUMBER):$(TARGET_BUILD_VARIANT)/$(BUILD_VERSION_TAGS)
+endif
+ifneq ($(words $(BUILD_THUMBPRINT)),1)
+  $(error BUILD_THUMBPRINT cannot contain spaces: "$(BUILD_THUMBPRINT)")
+endif
+
 # Display parameters shown under Settings -> About Phone
 ifeq ($(TARGET_BUILD_VARIANT),user)
   # User builds should show:
@@ -172,10 +181,17 @@
 else
 system_prop_file := $(wildcard $(TARGET_DEVICE_DIR)/system.prop)
 endif
-
 $(INSTALLED_BUILD_PROP_TARGET): $(BUILDINFO_SH) $(INTERNAL_BUILD_ID_MAKEFILE) $(BUILD_SYSTEM)/version_defaults.mk $(system_prop_file)
 	@echo Target buildinfo: $@
 	@mkdir -p $(dir $@)
+	$(hide) echo > $@
+ifneq ($(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_OEM_PROPERTIES),)
+	$(hide) echo "#" >> $@; \
+	        echo "# PRODUCT_OEM_PROPERTIES" >> $@; \
+	        echo "#" >> $@;
+	$(hide) $(foreach prop,$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_OEM_PROPERTIES), \
+		echo "import /oem/oem.prop $(prop)" >> $@;)
+endif
 	$(hide) TARGET_BUILD_TYPE="$(TARGET_BUILD_VARIANT)" \
 			TARGET_DEVICE="$(TARGET_DEVICE)" \
 			PRODUCT_NAME="$(TARGET_PRODUCT)" \
@@ -192,9 +208,11 @@
 			PLATFORM_VERSION="$(PLATFORM_VERSION)" \
 			PLATFORM_SDK_VERSION="$(PLATFORM_SDK_VERSION)" \
 			PLATFORM_VERSION_CODENAME="$(PLATFORM_VERSION_CODENAME)" \
+			PLATFORM_VERSION_ALL_CODENAMES="$(PLATFORM_VERSION_ALL_CODENAMES)" \
 			BUILD_VERSION_TAGS="$(BUILD_VERSION_TAGS)" \
 			TARGET_BOOTLOADER_BOARD_NAME="$(TARGET_BOOTLOADER_BOARD_NAME)" \
 			BUILD_FINGERPRINT="$(BUILD_FINGERPRINT)" \
+			BUILD_THUMBPRINT="$(BUILD_THUMBPRINT)" \
 			TARGET_BOARD_PLATFORM="$(TARGET_BOARD_PLATFORM)" \
 			TARGET_CPU_ABI_LIST="$(TARGET_CPU_ABI_LIST)" \
 			TARGET_CPU_ABI_LIST_32_BIT="$(TARGET_CPU_ABI_LIST_32_BIT)" \
@@ -202,7 +220,7 @@
 			TARGET_CPU_ABI="$(TARGET_CPU_ABI)" \
 			TARGET_CPU_ABI2="$(TARGET_CPU_ABI2)" \
 			TARGET_AAPT_CHARACTERISTICS="$(TARGET_AAPT_CHARACTERISTICS)" \
-	        bash $(BUILDINFO_SH) > $@
+	        bash $(BUILDINFO_SH) >> $@
 	$(hide) $(foreach file,$(system_prop_file), \
 		if [ -f "$(file)" ]; then \
 			echo "#" >> $@; \
@@ -218,11 +236,27 @@
 		        echo "#" >> $@; )
 	$(hide) $(foreach line,$(ADDITIONAL_BUILD_PROPERTIES), \
 		echo "$(line)" >> $@;)
-	$(hide) build/tools/post_process_props.py $@
+	$(hide) build/tools/post_process_props.py $@ $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_PROPERTY_BLACKLIST)
 
 build_desc :=
 
 # -----------------------------------------------------------------
+# vendor build.prop
+#
+# For verifying that the vendor build is what we thing it is
+ifdef BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE
+INSTALLED_VENDOR_BUILD_PROP_TARGET := $(TARGET_OUT_VENDOR)/build.prop
+ALL_DEFAULT_INSTALLED_MODULES += $(INSTALLED_VENDOR_BUILD_PROP_TARGET)
+$(INSTALLED_VENDOR_BUILD_PROP_TARGET): $(INSTALLED_BUILD_PROP_TARGET)
+	@echo Target vendor buildinfo: $@
+	@mkdir -p $(dir $@)
+	$(hide) echo > $@
+	$(hide) echo ro.vendor.build.date=`date`>>$@
+	$(hide) echo ro.vendor.build.date.utc=`date +%s`>>$@
+	$(hide) echo ro.vendor.build.fingerprint="$(BUILD_FINGERPRINT)">>$@
+endif
+
+# -----------------------------------------------------------------
 # sdk-build.prop
 #
 # There are certain things in build.prop that we don't want to
@@ -459,18 +493,33 @@
 	@echo "make $@: ignoring dependencies"
 	$(hide) $(MKEXT2BOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) --output $(INSTALLED_BOOTIMAGE_TARGET)
 
-else # TARGET_BOOTIMAGE_USE_EXT2 != true
+else ifeq (true,$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY)) # TARGET_BOOTIMAGE_USE_EXT2 != true
+
+$(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_FILES) $(BOOT_SIGNER)
+	$(call pretty,"Target boot image: $@")
+	$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@
+	$(BOOT_SIGNER) /boot $@ $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VERITY_SIGNING_KEY) $@
+	$(hide) $(call assert-max-image-size,$@,$(BOARD_BOOTIMAGE_PARTITION_SIZE))
+
+.PHONY: bootimage-nodeps
+bootimage-nodeps: $(MKBOOTIMG) $(BOOT_SIGNER)
+	@echo "make $@: ignoring dependencies"
+	$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(INSTALLED_BOOTIMAGE_TARGET)
+	$(BOOT_SIGNER) /boot $(INSTALLED_BOOTIMAGE_TARGET) $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VERITY_SIGNING_KEY) $(INSTALLED_BOOTIMAGE_TARGET)
+	$(hide) $(call assert-max-image-size,$(INSTALLED_BOOTIMAGE_TARGET),$(BOARD_BOOTIMAGE_PARTITION_SIZE))
+
+else # PRODUCT_SUPPORTS_VERITY != true
 
 $(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_FILES)
 	$(call pretty,"Target boot image: $@")
 	$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@
-	$(hide) $(call assert-max-image-size,$@,$(BOARD_BOOTIMAGE_PARTITION_SIZE),raw)
+	$(hide) $(call assert-max-image-size,$@,$(BOARD_BOOTIMAGE_PARTITION_SIZE))
 
 .PHONY: bootimage-nodeps
 bootimage-nodeps: $(MKBOOTIMG)
 	@echo "make $@: ignoring dependencies"
 	$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(INSTALLED_BOOTIMAGE_TARGET)
-	$(hide) $(call assert-max-image-size,$(INSTALLED_BOOTIMAGE_TARGET),$(BOARD_BOOTIMAGE_PARTITION_SIZE),raw)
+	$(hide) $(call assert-max-image-size,$(INSTALLED_BOOTIMAGE_TARGET),$(BOARD_BOOTIMAGE_PARTITION_SIZE))
 
 endif # TARGET_BOOTIMAGE_USE_EXT2
 
@@ -623,12 +672,21 @@
 endif
 
 ifeq ($(INTERNAL_USERIMAGES_USE_EXT),true)
-INTERNAL_USERIMAGES_DEPS := $(MKEXTUSERIMG) $(MAKE_EXT4FS) $(SIMG2IMG) $(E2FSCK)
+INTERNAL_USERIMAGES_DEPS := $(SIMG2IMG)
+INTERNAL_USERIMAGES_DEPS += $(MKEXTUSERIMG) $(MAKE_EXT4FS) $(E2FSCK)
+ifeq ($(TARGET_USERIMAGES_USE_F2FS),true)
+INTERNAL_USERIMAGES_DEPS += $(MKF2FSUSERIMG) $(MAKE_F2FS)
+endif
 else
 INTERNAL_USERIMAGES_DEPS := $(MKYAFFS2)
 endif
+
 INTERNAL_USERIMAGES_BINARY_PATHS := $(sort $(dir $(INTERNAL_USERIMAGES_DEPS)))
 
+ifeq (true,$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY))
+INTERNAL_USERIMAGES_DEPS += $(BUILD_VERITY_TREE) $(APPEND2SIMG) $(VERITY_SIGNER)
+endif
+
 SELINUX_FC := $(TARGET_ROOT_OUT)/file_contexts
 INTERNAL_USERIMAGES_DEPS += $(SELINUX_FC)
 
@@ -637,14 +695,21 @@
 define generate-userimage-prop-dictionary
 $(if $(INTERNAL_USERIMAGES_EXT_VARIANT),$(hide) echo "fs_type=$(INTERNAL_USERIMAGES_EXT_VARIANT)" >> $(1))
 $(if $(BOARD_SYSTEMIMAGE_PARTITION_SIZE),$(hide) echo "system_size=$(BOARD_SYSTEMIMAGE_PARTITION_SIZE)" >> $(1))
+$(if $(BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE),$(hide) echo "userdata_fs_type=$(BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE)" >> $(1))
 $(if $(BOARD_USERDATAIMAGE_PARTITION_SIZE),$(hide) echo "userdata_size=$(BOARD_USERDATAIMAGE_PARTITION_SIZE)" >> $(1))
 $(if $(BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE),$(hide) echo "cache_fs_type=$(BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE)" >> $(1))
 $(if $(BOARD_CACHEIMAGE_PARTITION_SIZE),$(hide) echo "cache_size=$(BOARD_CACHEIMAGE_PARTITION_SIZE)" >> $(1))
 $(if $(BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE),$(hide) echo "vendor_fs_type=$(BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE)" >> $(1))
 $(if $(BOARD_VENDORIMAGE_PARTITION_SIZE),$(hide) echo "vendor_size=$(BOARD_VENDORIMAGE_PARTITION_SIZE)" >> $(1))
+$(if $(BOARD_OEMIMAGE_PARTITION_SIZE),$(hide) echo "oem_size=$(BOARD_OEMIMAGE_PARTITION_SIZE)" >> $(1))
 $(if $(INTERNAL_USERIMAGES_SPARSE_EXT_FLAG),$(hide) echo "extfs_sparse_flag=$(INTERNAL_USERIMAGES_SPARSE_EXT_FLAG)" >> $(1))
 $(if $(mkyaffs2_extra_flags),$(hide) echo "mkyaffs2_extra_flags=$(mkyaffs2_extra_flags)" >> $(1))
 $(hide) echo "selinux_fc=$(SELINUX_FC)" >> $(1)
+$(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),$(hide) echo "verity=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY)" >> $(1))
+$(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),$(hide) echo "verity_key=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VERITY_SIGNING_KEY)" >> $(1))
+$(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),$(hide) echo "verity_signer_cmd=$(VERITY_SIGNER)" >> $(1))
+$(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_VERITY_PARTITION),$(hide) echo "system_verity_block_device=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_VERITY_PARTITION)" >> $(1))
+$(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VENDOR_VERITY_PARTITION),$(hide) echo "vendor_verity_block_device=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VENDOR_VERITY_PARTITION)" >> $(1))
 $(if $(2),$(hide) $(foreach kv,$(2),echo "$(kv)" >> $(1);))
 endef
 
@@ -664,11 +729,32 @@
 recovery_binary := $(call intermediates-dir-for,EXECUTABLES,recovery,,,$(TARGET_PREFER_32_BIT))/recovery
 recovery_resources_common := $(call include-path-for, recovery)/res
 
-# Select the 18x32 font on high-density devices; and the 12x22 font on
-# other devices.  Note that the font selected here can be overridden
-# for a particular device by putting a font.png in its private
-# recovery resources.
-ifneq (,$(filter xxhdpi xhdpi,$(subst $(comma),$(space),$(PRODUCT_AAPT_CONFIG))))
+# Set recovery_density to the density bucket of the device.
+recovery_density := unknown
+ifneq (,$(PRODUCT_AAPT_PREF_CONFIG))
+# If PRODUCT_AAPT_PREF_CONFIG includes a dpi bucket, then use that value.
+recovery_density := $(filter %dpi,$(PRODUCT_AAPT_PREF_CONFIG))
+else
+# Otherwise, use the highest density that appears in PRODUCT_AAPT_CONFIG.
+# Order is important here; we'll take the first one that's found.
+recovery_densities := $(filter $(PRODUCT_AAPT_CONFIG_SP),xxxhdpi xxhdpi xhdpi hdpi tvdpi mdpi ldpi)
+ifneq (,$(recovery_densities))
+recovery_density := $(word 1,$(recovery_densities))
+endif
+endif
+
+ifneq (,$(wildcard $(recovery_resources_common)-$(recovery_density)))
+recovery_resources_common := $(recovery_resources_common)-$(recovery_density)
+else
+recovery_resources_common := $(recovery_resources_common)-xhdpi
+endif
+
+# Select the 18x32 font on high-density devices (xhdpi and up); and
+# the 12x22 font on other devices.  Note that the font selected here
+# can be overridden for a particular device by putting a font.png in
+# its private recovery resources.
+
+ifneq (,$(filter xxxhdpi xxhdpi xhdpi,$(recovery_density)))
 recovery_font := $(call include-path-for, recovery)/fonts/18x32.png
 else
 recovery_font := $(call include-path-for, recovery)/fonts/12x22.png
@@ -750,7 +836,9 @@
 	$(hide) cp -f $(recovery_sepolicy) $(TARGET_RECOVERY_ROOT_OUT)/sepolicy
 	$(hide) -cp $(TARGET_ROOT_OUT)/init.recovery.*.rc $(TARGET_RECOVERY_ROOT_OUT)/
 	$(hide) cp -f $(recovery_binary) $(TARGET_RECOVERY_ROOT_OUT)/sbin/
-	$(hide) cp -rf $(recovery_resources_common) $(TARGET_RECOVERY_ROOT_OUT)/
+	$(hide) mkdir -p $(TARGET_RECOVERY_ROOT_OUT)/res
+	$(hide) rm -rf $(TARGET_RECOVERY_ROOT_OUT)/res/*
+	$(hide) cp -rf $(recovery_resources_common)/* $(TARGET_RECOVERY_ROOT_OUT)/res
 	$(hide) cp -f $(recovery_font) $(TARGET_RECOVERY_ROOT_OUT)/res/images/font.png
 	$(hide) $(foreach item,$(recovery_resources_private), \
 	  cp -rf $(item) $(TARGET_RECOVERY_ROOT_OUT)/)
@@ -761,7 +849,10 @@
 	        > $(TARGET_RECOVERY_ROOT_OUT)/default.prop
 	$(hide) $(MKBOOTFS) $(TARGET_RECOVERY_ROOT_OUT) | $(MINIGZIP) > $(recovery_ramdisk)
 	$(hide) $(MKBOOTIMG) $(INTERNAL_RECOVERYIMAGE_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@
-	$(hide) $(call assert-max-image-size,$@,$(BOARD_RECOVERYIMAGE_PARTITION_SIZE),raw)
+ifeq (true,$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY))
+	$(BOOT_SIGNER) /recovery $@ $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VERITY_SIGNING_KEY) $@
+endif
+	$(hide) $(call assert-max-image-size,$@,$(BOARD_RECOVERYIMAGE_PARTITION_SIZE))
 	@echo ----- Made recovery image: $@ --------
 
 $(RECOVERY_RESOURCE_ZIP): $(INSTALLED_RECOVERYIMAGE_TARGET)
@@ -828,14 +919,36 @@
     $(call intermediates-dir-for,PACKAGING,systemimage)
 BUILT_SYSTEMIMAGE := $(systemimage_intermediates)/system.img
 
+# Create symlink /system/vendor to /vendor if necessary.
+ifdef BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE
+define create-system-vendor-symlink
+$(hide) if [ -d $(TARGET_OUT)/vendor ] && [ ! -h $(TARGET_OUT)/vendor ]; then \
+  echo 'Non-symlink $(TARGET_OUT)/vendor detected!' 1>&2; \
+  echo 'You cannot install files to $(TARGET_OUT)/vendor while building a separate vendor.img!' 1>&2; \
+  exit 1; \
+fi
+$(hide) ln -sf /vendor $(TARGET_OUT)/vendor
+endef
+else
+define create-system-vendor-symlink
+endef
+endif
+
 # $(1): output file
 define build-systemimage-target
   @echo "Target system fs image: $(1)"
+  $(call create-system-vendor-symlink)
   @mkdir -p $(dir $(1)) $(systemimage_intermediates) && rm -rf $(systemimage_intermediates)/system_image_info.txt
-  $(call generate-userimage-prop-dictionary, $(systemimage_intermediates)/system_image_info.txt, skip_fsck=true)
+  $(call generate-userimage-prop-dictionary, $(systemimage_intermediates)/system_image_info.txt, \
+      skip_fsck=true)
   $(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH \
       ./build/tools/releasetools/build_image.py \
-      $(TARGET_OUT) $(systemimage_intermediates)/system_image_info.txt $(1)
+      $(TARGET_OUT) $(systemimage_intermediates)/system_image_info.txt $(1) \
+      || ( echo "Out of space? the tree size of $(TARGET_OUT) is (MB): " 1>&2 ;\
+           du -sm $(TARGET_OUT) 1>&2;\
+           echo "The max is $$(( $(BOARD_SYSTEMIMAGE_PARTITION_SIZE) / 1048576 )) MB." 1>&2 ;\
+           mkdir -p $(DIST_DIR); cp $(INSTALLED_FILES_FILE) $(DIST_DIR)/installed-files-rescued.txt; \
+           exit 1 )
 endef
 
 $(BUILT_SYSTEMIMAGE): $(FULL_SYSTEMIMAGE_DEPS) $(INSTALLED_FILES_FILE)
@@ -865,7 +978,7 @@
 $(INSTALLED_SYSTEMIMAGE): $(BUILT_SYSTEMIMAGE) $(RECOVERY_FROM_BOOT_PATCH) | $(ACP)
 	@echo "Install system fs image: $@"
 	$(copy-file-to-target)
-	$(hide) $(call assert-max-image-size,$@ $(RECOVERY_FROM_BOOT_PATCH),$(BOARD_SYSTEMIMAGE_PARTITION_SIZE),yaffs)
+	$(hide) $(call assert-max-image-size,$@ $(RECOVERY_FROM_BOOT_PATCH),$(BOARD_SYSTEMIMAGE_PARTITION_SIZE))
 
 systemimage: $(INSTALLED_SYSTEMIMAGE)
 
@@ -874,7 +987,7 @@
 	            | $(INTERNAL_USERIMAGES_DEPS)
 	@echo "make $@: ignoring dependencies"
 	$(call build-systemimage-target,$(INSTALLED_SYSTEMIMAGE))
-	$(hide) $(call assert-max-image-size,$(INSTALLED_SYSTEMIMAGE),$(BOARD_SYSTEMIMAGE_PARTITION_SIZE),yaffs)
+	$(hide) $(call assert-max-image-size,$(INSTALLED_SYSTEMIMAGE),$(BOARD_SYSTEMIMAGE_PARTITION_SIZE))
 
 ifneq (,$(filter systemimage-nodeps snod, $(MAKECMDGOALS)))
 ifeq (true,$(WITH_DEXPREOPT))
@@ -885,10 +998,11 @@
 #######
 ## system tarball
 define build-systemtarball-target
-    $(call pretty,"Target system fs tarball: $(INSTALLED_SYSTEMTARBALL_TARGET)")
-    $(MKTARBALL) $(FS_GET_STATS) \
-		$(PRODUCT_OUT) system $(PRIVATE_SYSTEM_TAR) \
-		$(INSTALLED_SYSTEMTARBALL_TARGET)
+  $(call pretty,"Target system fs tarball: $(INSTALLED_SYSTEMTARBALL_TARGET)")
+  $(call create-system-vendor-symlink)
+  $(MKTARBALL) $(FS_GET_STATS) \
+    $(PRODUCT_OUT) system $(PRIVATE_SYSTEM_TAR) \
+    $(INSTALLED_SYSTEMTARBALL_TARGET)
 endef
 
 ifndef SYSTEM_TARBALL_FORMAT
@@ -909,11 +1023,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
@@ -930,7 +1039,11 @@
 		$(TARGET_COPY_OUT_SYSTEM) \
 		$(patsubst $(PRODUCT_OUT)/%, %, $(TARGET_OUT_NOTICE_FILES)) \
 		$(addprefix symbols/,$(PDK_SYMBOL_FILES_LIST))
-ifeq (true,$(PLATFORM_ZIP_ADD_JAVA))
+ifdef BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE
+	$(hide) cd $(dir $@) && zip -qry $(notdir $@) \
+		$(TARGET_COPY_OUT_VENDOR)
+endif
+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),)
@@ -1002,7 +1115,7 @@
   $(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH \
       ./build/tools/releasetools/build_image.py \
       $(TARGET_OUT_DATA) $(userdataimage_intermediates)/userdata_image_info.txt $(INSTALLED_USERDATAIMAGE_TARGET)
-  $(hide) $(call assert-max-image-size,$(INSTALLED_USERDATAIMAGE_TARGET),$(BOARD_USERDATAIMAGE_PARTITION_SIZE),yaffs)
+  $(hide) $(call assert-max-image-size,$(INSTALLED_USERDATAIMAGE_TARGET),$(BOARD_USERDATAIMAGE_PARTITION_SIZE))
 endef
 
 # We just build this directly to the install location.
@@ -1057,7 +1170,7 @@
   $(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH \
       ./build/tools/releasetools/build_image.py \
       $(TARGET_OUT_CACHE) $(cacheimage_intermediates)/cache_image_info.txt $(INSTALLED_CACHEIMAGE_TARGET)
-  $(hide) $(call assert-max-image-size,$(INSTALLED_CACHEIMAGE_TARGET),$(BOARD_CACHEIMAGE_PARTITION_SIZE),yaffs)
+  $(hide) $(call assert-max-image-size,$(INSTALLED_CACHEIMAGE_TARGET),$(BOARD_CACHEIMAGE_PARTITION_SIZE))
 endef
 
 # We just build this directly to the install location.
@@ -1076,7 +1189,12 @@
 # vendor partition image
 ifdef BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE
 INTERNAL_VENDORIMAGE_FILES := \
-    $(filter $(TARGET_OUT_VENDOR)/%,$(ALL_DEFAULT_INSTALLED_MODULES))
+    $(filter $(TARGET_OUT_VENDOR)/%,\
+      $(ALL_DEFAULT_INSTALLED_MODULES)\
+      $(ALL_PDK_FUSION_FILES))
+
+# platform.zip depends on $(INTERNAL_VENDORIMAGE_FILES).
+$(INSTALLED_PLATFORM_ZIP) : $(INTERNAL_VENDORIMAGE_FILES)
 
 vendorimage_intermediates := \
     $(call intermediates-dir-for,PACKAGING,vendor)
@@ -1090,7 +1208,7 @@
   $(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH \
       ./build/tools/releasetools/build_image.py \
       $(TARGET_OUT_VENDOR) $(vendorimage_intermediates)/vendor_image_info.txt $(INSTALLED_VENDORIMAGE_TARGET)
-  $(hide) $(call assert-max-image-size,$(INSTALLED_VENDORIMAGE_TARGET),$(BOARD_VENDORIMAGE_PARTITION_SIZE),yaffs)
+  $(hide) $(call assert-max-image-size,$(INSTALLED_VENDORIMAGE_TARGET),$(BOARD_VENDORIMAGE_PARTITION_SIZE))
 endef
 
 # We just build this directly to the install location.
@@ -1120,7 +1238,11 @@
 	  $(HOST_OUT_EXECUTABLES)/mkuserimg.sh \
 	  $(HOST_OUT_EXECUTABLES)/make_ext4fs \
 	  $(HOST_OUT_EXECUTABLES)/simg2img \
-	  $(HOST_OUT_EXECUTABLES)/e2fsck
+	  $(HOST_OUT_EXECUTABLES)/e2fsck \
+	  $(HOST_OUT_EXECUTABLES)/build_verity_tree \
+	  $(HOST_OUT_EXECUTABLES)/verity_signer \
+	  $(HOST_OUT_EXECUTABLES)/append2simg \
+	  $(HOST_OUT_EXECUTABLES)/boot_signer
 
 OTATOOLS := $(DISTTOOLS) \
 	  $(HOST_OUT_EXECUTABLES)/aapt
@@ -1276,18 +1398,32 @@
 	$(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
+	$(hide) echo "blockimgdiff_versions=1,2" >> $(zip_root)/META/misc_info.txt
+ifneq ($(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_OEM_PROPERTIES),)
+	# OTA scripts are only interested in fingerprint related properties
+ifneq ($(filter ro.product.brand ro.product.name ro.product.device, $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_OEM_PROPERTIES)),)
+	$(hide) echo "oem_fingerprint_properties=$(filter ro.product.brand ro.product.name ro.product.device, $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_OEM_PROPERTIES))" >> $(zip_root)/META/misc_info.txt
+endif
+endif
 	$(call generate-userimage-prop-dictionary, $(zip_root)/META/misc_info.txt)
+	$(hide) ./build/tools/releasetools/make_recovery_patch $(zip_root) $(zip_root)
 	@# Zip everything up, preserving symlinks
 	$(hide) (cd $(zip_root) && zip -qry ../$(notdir $@) .)
-	@# Run fs_config on all the system, boot ramdisk, and recovery ramdisk files in the zip, and save the output
+	@# Run fs_config on all the system, vendor, boot ramdisk,
+	@# and recovery ramdisk files in the zip, and save the output
 	$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="SYSTEM/" } /^SYSTEM\// {print "system/" $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -S $(SELINUX_FC) > $(zip_root)/META/filesystem_config.txt
+	$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="VENDOR/" } /^VENDOR\// {print "vendor/" $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -S $(SELINUX_FC) > $(zip_root)/META/vendor_filesystem_config.txt
 	$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="BOOT/RAMDISK/" } /^BOOT\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -S $(SELINUX_FC) > $(zip_root)/META/boot_filesystem_config.txt
 	$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="RECOVERY/RAMDISK/" } /^RECOVERY\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -S $(SELINUX_FC) > $(zip_root)/META/recovery_filesystem_config.txt
 	$(hide) (cd $(zip_root) && zip -q ../$(notdir $@) META/*filesystem_config.txt)
+	$(hide) ./build/tools/releasetools/add_img_to_target_files -p $(HOST_OUT) $@
 
 .PHONY: target-files-package
 target-files-package: $(BUILT_TARGET_FILES_PACKAGE)
 
+ifneq ($(filter $(MAKECMDGOALS),target-files-package),)
+$(call dist-for-goals, target-files-package, $(BUILT_TARGET_FILES_PACKAGE))
+endif
 
 ifneq ($(TARGET_PRODUCT),sdk)
 ifeq ($(filter generic%,$(TARGET_DEVICE)),)
@@ -1311,13 +1447,20 @@
 	@echo "Package OTA: $@"
 	$(hide) MKBOOTIMG=$(MKBOOTIMG) \
 	   ./build/tools/releasetools/ota_from_target_files -v \
+	   --block \
 	   -p $(HOST_OUT) \
 	   -k $(KEY_CERT_PAIR) \
+	   $(if $(OEM_OTA_CONFIG), -o $(OEM_OTA_CONFIG)) \
 	   $(BUILT_TARGET_FILES_PACKAGE) $@
 
 .PHONY: otapackage
 otapackage: $(INTERNAL_OTA_PACKAGE_TARGET)
 
+endif    # recovery_fstab is defined
+endif    # TARGET_NO_KERNEL != true
+endif    # TARGET_DEVICE != generic*
+endif    # TARGET_PRODUCT != sdk
+
 # -----------------------------------------------------------------
 # The update package
 
@@ -1329,29 +1472,16 @@
 
 INTERNAL_UPDATE_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name).zip
 
-ifeq ($(TARGET_RELEASETOOLS_EXTENSIONS),)
-# default to common dir for device vendor
-$(INTERNAL_UPDATE_PACKAGE_TARGET): extensions := $(TARGET_DEVICE_DIR)/../common
-else
-$(INTERNAL_UPDATE_PACKAGE_TARGET): extensions := $(TARGET_RELEASETOOLS_EXTENSIONS)
-endif
-
 $(INTERNAL_UPDATE_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(DISTTOOLS)
 	@echo "Package: $@"
 	$(hide) MKBOOTIMG=$(MKBOOTIMG) \
 	   ./build/tools/releasetools/img_from_target_files -v \
-	   -s $(extensions) \
 	   -p $(HOST_OUT) \
 	   $(BUILT_TARGET_FILES_PACKAGE) $@
 
 .PHONY: updatepackage
 updatepackage: $(INTERNAL_UPDATE_PACKAGE_TARGET)
 
-endif    # recovery_fstab is defined
-endif    # TARGET_NO_KERNEL != true
-endif    # TARGET_DEVICE != generic*
-endif    # TARGET_PRODUCT != sdk
-
 # -----------------------------------------------------------------
 # A zip of the symbols directory.  Keep the full paths to make it
 # more obvious where these files came from.
@@ -1384,7 +1514,7 @@
 	@echo "Package apps: $@"
 	$(hide) rm -rf $@
 	$(hide) mkdir -p $(dir $@)
-	$(hide) zip -qj $@ $(TARGET_OUT_APPS)/* $(TARGET_OUT_APPS_PRIVILEGED)/*
+	$(hide) zip -qj $@ $(TARGET_OUT_APPS)/*/*.apk $(TARGET_OUT_APPS_PRIVILEGED)/*/*.apk
 
 
 #------------------------------------------------------------------
@@ -1396,7 +1526,7 @@
 # the dependency will be set up later in build/core/main.mk.
 $(EMMA_META_ZIP) :
 	@echo "Collecting Emma coverage meta files."
-	$(hide) find $(TARGET_COMMON_OUT_ROOT) -name "coverage.em" | \
+	$(hide) find $(TARGET_COMMON_OUT_ROOT) $(HOST_COMMON_OUT_ROOT) -name "coverage.em" | \
 		zip -@ -q $@
 
 endif # EMMA_INSTRUMENT=true
@@ -1412,7 +1542,8 @@
 	@echo "Packaging Proguard obfuscation dictionary files."
 	$(hide) dict_files=`find $(TARGET_OUT_COMMON_INTERMEDIATES)/APPS -name proguard_dictionary`; \
 		if [ -n "$$dict_files" ]; then \
-		  zip -q $@ $$dict_files; \
+		  unobfuscated_jars=$${dict_files//proguard_dictionary/classes.jar}; \
+		  zip -q $@ $$dict_files $$unobfuscated_jars; \
 		else \
 		  touch $(dir $@)/dummy; \
 		  (cd $(dir $@) && zip -q $(notdir $@) dummy); \
@@ -1488,7 +1619,6 @@
 ATREE_FILES := \
 	$(ALL_PREBUILT) \
 	$(ALL_COPIED_HEADERS) \
-	$(ALL_GENERATED_SOURCES) \
 	$(ALL_DEFAULT_INSTALLED_MODULES) \
 	$(INSTALLED_RAMDISK_TARGET) \
 	$(ALL_DOCS) \
@@ -1500,7 +1630,6 @@
 
 sdk_atree_files := \
 	$(atree_dir)/sdk.exclude.atree \
-	$(atree_dir)/sdk.atree \
 	$(atree_dir)/sdk-$(HOST_OS)-$(SDK_HOST_ARCH).atree
 
 # development/build/sdk-android-<abi>.atree is used to differentiate
@@ -1511,6 +1640,14 @@
   sdk_atree_files += $(atree_dir)/sdk-android-$(TARGET_CPU_ABI).atree
 endif
 
+ifneq ($(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SDK_ATREE_FILES),)
+sdk_atree_files += $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SDK_ATREE_FILES)
+else
+sdk_atree_files += $(atree_dir)/sdk.atree
+endif
+
+include $(BUILD_SYSTEM)/sdk_font.mk
+
 deps := \
 	$(target_notice_file_txt) \
 	$(tools_notice_file_txt) \
@@ -1522,9 +1659,10 @@
 	$(INSTALLED_SDK_BUILD_PROP_TARGET) \
 	$(INSTALLED_BUILD_PROP_TARGET) \
 	$(ATREE_FILES) \
-	$(atree_dir)/sdk.atree \
+	$(sdk_atree_files) \
 	$(HOST_OUT_EXECUTABLES)/atree \
-	$(HOST_OUT_EXECUTABLES)/line_endings
+	$(HOST_OUT_EXECUTABLES)/line_endings \
+	$(SDK_FONT_DEPS)
 
 INTERNAL_SDK_TARGET := $(sdk_dir)/$(sdk_name).zip
 $(INTERNAL_SDK_TARGET): PRIVATE_NAME := $(sdk_name)
@@ -1547,6 +1685,7 @@
 	  fi; \
 	done; \
 	if [ $$FAIL ]; then exit 1; fi
+	$(hide) echo $(notdir $(SDK_FONT_DEPS)) | tr " " "\n"  > $(SDK_FONT_TEMP)/fontsInSdk.txt
 	$(hide) ( \
 		ATREE_STRIP="strip -x" \
 		$(HOST_OUT_EXECUTABLES)/atree \
@@ -1562,6 +1701,7 @@
 			-v "TARGET_ARCH=$(TARGET_ARCH)" \
 			-v "TARGET_CPU_ABI=$(TARGET_CPU_ABI)" \
 			-v "DLL_EXTENSION=$(HOST_SHLIB_SUFFIX)" \
+			-v "FONT_OUT=$(SDK_FONT_TEMP)" \
 			-o $(PRIVATE_DIR) && \
 		cp -f $(target_notice_file_txt) \
 				$(PRIVATE_DIR)/system-images/android-$(PLATFORM_VERSION)/$(TARGET_CPU_ABI)/NOTICE.txt && \
@@ -1588,11 +1728,11 @@
 INTERNAL_FINDBUGS_HTML_TARGET := $(PRODUCT_OUT)/findbugs.html
 $(INTERNAL_FINDBUGS_XML_TARGET): $(ALL_FINDBUGS_FILES)
 	@echo UnionBugs: $@
-	$(hide) prebuilt/common/findbugs/bin/unionBugs $(ALL_FINDBUGS_FILES) \
+	$(hide) $(FINDBUGS_DIR)/unionBugs $(ALL_FINDBUGS_FILES) \
 	> $@
 $(INTERNAL_FINDBUGS_HTML_TARGET): $(INTERNAL_FINDBUGS_XML_TARGET)
 	@echo ConvertXmlToText: $@
-	$(hide) prebuilt/common/findbugs/bin/convertXmlToText -html:fancy.xsl \
+	$(hide) $(FINDBUGS_DIR)/convertXmlToText -html:fancy.xsl \
 	$(INTERNAL_FINDBUGS_XML_TARGET) > $@
 
 # -----------------------------------------------------------------
@@ -1604,6 +1744,9 @@
 include $(sort $(wildcard $(BUILD_SYSTEM)/tasks/*.mk))
 -include $(sort $(wildcard vendor/*/build/tasks/*.mk))
 -include $(sort $(wildcard device/*/build/tasks/*.mk))
+# Also the project-specific tasks
+-include $(sort $(wildcard vendor/*/*/build/tasks/*.mk))
+-include $(sort $(wildcard device/*/*/build/tasks/*.mk))
 endif
 
 # -----------------------------------------------------------------
diff --git a/core/android_manifest.mk b/core/android_manifest.mk
new file mode 100644
index 0000000..21b95c2
--- /dev/null
+++ b/core/android_manifest.mk
@@ -0,0 +1,25 @@
+# Handle AndroidManifest.xmls
+# Input: LOCAL_MANIFEST_FILE, LOCAL_FULL_MANIFEST_FILE, LOCAL_FULL_LIBS_MANIFEST_FILES
+# Output: full_android_manifest
+
+ifeq ($(strip $(LOCAL_MANIFEST_FILE)),)
+  LOCAL_MANIFEST_FILE := AndroidManifest.xml
+endif
+ifdef LOCAL_FULL_MANIFEST_FILE
+  full_android_manifest := $(LOCAL_FULL_MANIFEST_FILE)
+else
+  full_android_manifest := $(LOCAL_PATH)/$(LOCAL_MANIFEST_FILE)
+endif
+
+# Set up rules to merge library manifest files
+ifdef LOCAL_FULL_LIBS_MANIFEST_FILES
+main_android_manifest := $(full_android_manifest)
+full_android_manifest := $(intermediates.COMMON)/AndroidManifest.xml
+$(full_android_manifest): PRIVATE_LIBS_MANIFESTS := $(LOCAL_FULL_LIBS_MANIFEST_FILES)
+$(full_android_manifest) : $(main_android_manifest) $(LOCAL_FULL_LIBS_MANIFEST_FILES)
+	@echo "Merge android manifest files: $@ <-- $^"
+	@mkdir -p $(dir $@)
+	$(hide) $(ANDROID_MANIFEST_MERGER) --main $< --libs $(PRIVATE_LIBS_MANIFESTS) \
+	    --out $@
+
+endif
diff --git a/core/apicheck_msg_current.txt b/core/apicheck_msg_current.txt
index 440e7f8..9abd381 100644
--- a/core/apicheck_msg_current.txt
+++ b/core/apicheck_msg_current.txt
@@ -7,7 +7,7 @@
       errors above.
 
    2) You can update current.txt by executing the following command:
-         make update-api
+         make %UPDATE_API%
 
       To submit the revised current.txt to the main Android repository,
       you will need approval.
diff --git a/core/base_rules.mk b/core/base_rules.mk
index 6ab59f3..a709365 100644
--- a/core/base_rules.mk
+++ b/core/base_rules.mk
@@ -114,6 +114,8 @@
   else
   ifeq (true,$(LOCAL_PROPRIETARY_MODULE))
     partition_tag := _VENDOR
+  else ifeq (true,$(LOCAL_OEM_MODULE))
+    partition_tag := _OEM
   else
     # The definition of should-install-to-system will be different depending
     # on which goal (e.g., sdk or just droid) is being built.
@@ -174,9 +176,15 @@
   built_module_path := $(intermediates)
 endif
 LOCAL_BUILT_MODULE := $(built_module_path)/$(my_built_module_stem)
-built_module_path :=
 
 ifneq (true,$(LOCAL_UNINSTALLABLE_MODULE))
+  # Apk and its attachments reside in its own subdir.
+  ifeq ($(LOCAL_MODULE_CLASS),APPS)
+  # framework-res.apk doesn't like the additional layer.
+  ifneq ($(LOCAL_NO_STANDARD_LIBRARIES),true)
+    my_module_path := $(my_module_path)/$(LOCAL_MODULE)
+  endif
+  endif
   LOCAL_INSTALLED_MODULE := $(my_module_path)/$(my_installed_module_stem)
 endif
 
@@ -198,12 +206,12 @@
 aidl_preprocess_import :=
 LOCAL_SDK_VERSION:=$(strip $(LOCAL_SDK_VERSION))
 ifdef LOCAL_SDK_VERSION
-ifeq ($(LOCAL_SDK_VERSION)$(TARGET_BUILD_APPS),current)
+ifneq ($(filter current system_current, $(LOCAL_SDK_VERSION)$(TARGET_BUILD_APPS)),)
   # LOCAL_SDK_VERSION is current and no TARGET_BUILD_APPS
   aidl_preprocess_import := $(TARGET_OUT_COMMON_INTERMEDIATES)/framework.aidl
 else
   aidl_preprocess_import := $(HISTORICAL_SDK_VERSIONS_ROOT)/$(LOCAL_SDK_VERSION)/framework.aidl
-endif # !current
+endif # not current or system_current
 else
 # build against the platform.
 LOCAL_AIDL_INCLUDES += $(FRAMEWORKS_BASE_JAVA_SRC_DIRS)
@@ -230,7 +238,7 @@
 
 # Emit a java source file with constants for the tags, if
 # LOCAL_MODULE_CLASS is "APPS" or "JAVA_LIBRARIES".
-ifneq ($(strip $(filter $(LOCAL_MODULE_CLASS),APPS JAVA_LIBRARIES)),)
+ifneq ($(filter $(LOCAL_MODULE_CLASS),APPS JAVA_LIBRARIES),)
 
 logtags_java_sources := $(patsubst %.logtags,%.java,$(addprefix $(intermediates.COMMON)/src/, $(logtags_sources)))
 logtags_sources := $(addprefix $(TOP_DIR)$(LOCAL_PATH)/, $(logtags_sources))
@@ -386,13 +394,14 @@
 ifeq ($(LOCAL_SDK_VERSION)$(TARGET_BUILD_APPS),current)
 # LOCAL_SDK_VERSION is current and no TARGET_BUILD_APPS.
 $(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_BOOTCLASSPATH := -bootclasspath $(call java-lib-files,android_stubs_current)
+else ifeq ($(LOCAL_SDK_VERSION)$(TARGET_BUILD_APPS),system_current)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_BOOTCLASSPATH := -bootclasspath $(call java-lib-files,android_system_stubs_current)
 else
 $(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_BOOTCLASSPATH := -bootclasspath $(call java-lib-files,sdk_v$(LOCAL_SDK_VERSION))
-endif # current
+endif # current or system_current
 endif # LOCAL_SDK_VERSION
 endif # TARGET_
 $(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_RESOURCE_DIR := $(LOCAL_RESOURCE_DIR)
-$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_EXTRA_JAR_ARGS := $(extra_jar_args)
 $(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_ASSET_DIR := $(LOCAL_ASSET_DIR)
 $(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_STATIC_JAVA_LIBRARIES := $(full_static_java_libs)
 
@@ -423,10 +432,10 @@
 
 # This is set by packages that are linking to other packages that export
 # shared libraries, allowing them to make use of the code in the linked apk.
-LOCAL_APK_LIBRARIES := $(strip $(LOCAL_APK_LIBRARIES))
-ifdef LOCAL_APK_LIBRARIES
+apk_libraries := $(sort $(LOCAL_APK_LIBRARIES) $(LOCAL_RES_LIBRARIES))
+ifneq ($(apk_libraries),)
   link_apk_libraries := \
-      $(foreach lib,$(LOCAL_APK_LIBRARIES), \
+      $(foreach lib,$(apk_libraries), \
         $(call intermediates-dir-for, \
               APPS,$(lib),,COMMON)/classes.jar)
 
@@ -454,6 +463,10 @@
   full_java_lib_deps += $(link_instr_classes_jar)
 endif
 
+endif  # need_compile_java
+
+# We may want to add jar manifest or jar resource files even if there is no java code at all.
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_EXTRA_JAR_ARGS := $(extra_jar_args)
 jar_manifest_file :=
 ifneq ($(strip $(LOCAL_JAR_MANIFEST)),)
 jar_manifest_file := $(LOCAL_PATH)/$(LOCAL_JAR_MANIFEST)
@@ -462,9 +475,6 @@
 $(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_JAR_MANIFEST :=
 endif
 
-endif  # need_compile_java
-
-
 ###########################################################
 ## make clean- targets
 ###########################################################
@@ -598,7 +608,7 @@
 ALL_MODULES.$(my_register_name).INSTALLED := \
     $(strip $(ALL_MODULES.$(my_register_name).INSTALLED) $(LOCAL_INSTALLED_MODULE))
 ALL_MODULES.$(my_register_name).BUILT_INSTALLED := \
-    $(strip $(ALL_MODULES.$(my_register_name).BUILT_INSTALLED)$(LOCAL_BUILT_MODULE):$(LOCAL_INSTALLED_MODULE))
+    $(strip $(ALL_MODULES.$(my_register_name).BUILT_INSTALLED) $(LOCAL_BUILT_MODULE):$(LOCAL_INSTALLED_MODULE))
 endif
 ifdef LOCAL_PICKUP_FILES
 # Files or directories ready to pick up by the build system
@@ -622,6 +632,9 @@
 ifdef LOCAL_2ND_ARCH_VAR_PREFIX
 ALL_MODULES.$(my_register_name).FOR_2ND_ARCH := true
 endif
+ifdef aidl_sources
+ALL_MODULES.$(my_register_name).AIDL_FILES := $(aidl_sources)
+endif
 
 INSTALLABLE_FILES.$(LOCAL_INSTALLED_MODULE).MODULE := $(my_register_name)
 
diff --git a/core/binary.mk b/core/binary.mk
index efb0db0..ed09a24 100644
--- a/core/binary.mk
+++ b/core/binary.mk
@@ -179,6 +179,8 @@
 
 ifeq ($(strip $(LOCAL_ADDRESS_SANITIZER)),true)
   my_clang := true
+  # Frame pointer based unwinder in ASan requires ARM frame setup.
+  LOCAL_ARM_MODE := arm
   my_cflags += $(ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS)
   my_ldflags += $(ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS)
   my_shared_libraries += $(ADDRESS_SANITIZER_CONFIG_EXTRA_SHARED_LIBRARIES)
@@ -196,11 +198,13 @@
 
 ####################################################
 ## Add FDO flags if FDO is turned on and supported
-####################################################
-ifneq ($(strip $(LOCAL_FDO_SUPPORT)),)
+## Please note that we will do option filtering during FDO build.
+## i.e. Os->O2, remove -fno-early-inline and -finline-limit.
+##################################################################
+ifeq ($(strip $(LOCAL_FDO_SUPPORT)), true)
   ifeq ($(strip $(LOCAL_IS_HOST_MODULE)),)
     my_cflags += $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_FDO_CFLAGS)
-    my_ldflags += $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_FDO_CFLAGS)
+    my_ldflags += $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_FDO_LDFLAGS)
   endif
 endif
 
@@ -444,6 +448,8 @@
 # This can be disabled with LOCAL_RENDERSCRIPT_FLAGS := -Wno-error
 renderscript_flags := -Wall -Werror
 renderscript_flags += $(LOCAL_RENDERSCRIPT_FLAGS)
+# -m32 or -m64
+renderscript_flags += -m$(my_32_64_bit_suffix)
 
 renderscript_includes := \
     $(TOPDIR)external/clang/lib/Headers \
@@ -514,6 +520,9 @@
 proto_generated_objects := $(addprefix $(proto_generated_obj_dir)/, \
     $(patsubst %.proto,%.pb.o,$(proto_sources_fullpath)))
 
+# Auto-export the generated proto source dir.
+LOCAL_EXPORT_C_INCLUDE_DIRS += $(proto_generated_cc_sources_dir)
+
 # Ensure the transform-proto-to-cc rule is only defined once in multilib build.
 ifndef $(my_prefix)_$(LOCAL_MODULE_CLASS)_$(LOCAL_MODULE)_proto_defined
 $(proto_generated_cc_sources): PRIVATE_PROTO_INCLUDES := $(TOP)
@@ -953,6 +962,21 @@
 my_ldflags := $(call $(LOCAL_2ND_ARCH_VAR_PREFIX)convert-to-$(my_host)clang-flags,$(my_ldflags))
 endif
 
+ifeq ($(LOCAL_FDO_SUPPORT), true)
+  build_with_fdo := false
+  ifeq ($(BUILD_FDO_INSTRUMENT), true)
+    build_with_fdo := true
+  endif
+  ifeq ($(BUILD_FDO_OPTIMIZE), true)
+    build_with_fdo := true
+  endif
+  ifeq ($(build_with_fdo), true)
+    my_cflags := $(patsubst -Os,-O2,$(my_cflags))
+    fdo_incompatible_flags=-fno-early-inlining -finline-limit=%
+    my_cflags := $(filter-out $(fdo_incompatible_flags),$(my_cflags))
+  endif
+endif
+
 $(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_YACCFLAGS := $(LOCAL_YACCFLAGS)
 $(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_ASFLAGS := $(my_asflags)
 $(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_CONLYFLAGS := $(LOCAL_CONLYFLAGS)
@@ -993,7 +1017,8 @@
 ###########################################################
 export_includes := $(intermediates)/export_includes
 $(export_includes): PRIVATE_EXPORT_C_INCLUDE_DIRS := $(LOCAL_EXPORT_C_INCLUDE_DIRS)
-$(export_includes) : $(LOCAL_MODULE_MAKEFILE)
+# Make sure .pb.h are already generated before any dependent source files get compiled.
+$(export_includes) : $(LOCAL_MODULE_MAKEFILE) $(proto_generated_headers)
 	@echo Export includes file: $< -- $@
 	$(hide) mkdir -p $(dir $@) && rm -f $@
 ifdef LOCAL_EXPORT_C_INCLUDE_DIRS
diff --git a/core/build_id.mk b/core/build_id.mk
index f94b224..00a691f 100644
--- a/core/build_id.mk
+++ b/core/build_id.mk
@@ -18,6 +18,4 @@
 # (like "CRB01").  It must be a single word, and is
 # capitalized by convention.
 
-BUILD_ID := AOSP
-
-DISPLAY_BUILD_NUMBER := true
+export BUILD_ID=LMP
diff --git a/core/clang/config.mk b/core/clang/config.mk
index bdd18d8..d07df70 100644
--- a/core/clang/config.mk
+++ b/core/clang/config.mk
@@ -14,8 +14,8 @@
 LLVM_AS := $(LLVM_PREBUILTS_PATH)/llvm-as$(BUILD_EXECUTABLE_SUFFIX)
 LLVM_LINK := $(LLVM_PREBUILTS_PATH)/llvm-link$(BUILD_EXECUTABLE_SUFFIX)
 
-CLANG_TBLGEN := $(HOST_OUT_EXECUTABLES)/clang-tblgen$(BUILD_EXECUTABLE_SUFFIX)
-LLVM_TBLGEN := $(HOST_OUT_EXECUTABLES)/llvm-tblgen$(BUILD_EXECUTABLE_SUFFIX)
+CLANG_TBLGEN := $(BUILD_OUT_EXECUTABLES)/clang-tblgen$(BUILD_EXECUTABLE_SUFFIX)
+LLVM_TBLGEN := $(BUILD_OUT_EXECUTABLES)/llvm-tblgen$(BUILD_EXECUTABLE_SUFFIX)
 
 # The C/C++ compiler can be wrapped by setting the CC/CXX_WRAPPER vars.
 ifdef CC_WRAPPER
@@ -90,9 +90,10 @@
 endif
 
 # Address sanitizer clang config
-ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS := -fsanitize=address
+ADDRESS_SANITIZER_RUNTIME_LIBRARY := libclang_rt.asan_$(TARGET_ARCH)_android
+ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS := -fsanitize=address -fno-omit-frame-pointer
 ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS := -Wl,-u,__asan_preinit
-ADDRESS_SANITIZER_CONFIG_EXTRA_SHARED_LIBRARIES := libdl libasan_preload
+ADDRESS_SANITIZER_CONFIG_EXTRA_SHARED_LIBRARIES := libdl $(ADDRESS_SANITIZER_RUNTIME_LIBRARY)
 ADDRESS_SANITIZER_CONFIG_EXTRA_STATIC_LIBRARIES := libasan
 
 # This allows us to use the superset of functionality that compiler-rt
diff --git a/core/cleanbuild.mk b/core/cleanbuild.mk
index 8731457..c820ad5 100644
--- a/core/cleanbuild.mk
+++ b/core/cleanbuild.mk
@@ -214,13 +214,17 @@
 	$(PRODUCT_OUT)/recovery \
 	$(PRODUCT_OUT)/root \
 	$(PRODUCT_OUT)/system \
+	$(PRODUCT_OUT)/vendor \
+	$(PRODUCT_OUT)/oem \
 	$(PRODUCT_OUT)/dex_bootjars \
 	$(PRODUCT_OUT)/obj/JAVA_LIBRARIES \
 	$(PRODUCT_OUT)/obj/FAKE \
 	$(PRODUCT_OUT)/obj/EXECUTABLES/adbd_intermediates \
+	$(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libfs_mgr_intermediates \
 	$(PRODUCT_OUT)/obj/EXECUTABLES/init_intermediates \
 	$(PRODUCT_OUT)/obj/ETC/mac_permissions.xml_intermediates \
-	$(PRODUCT_OUT)/obj/ETC/sepolicy_intermediates
+	$(PRODUCT_OUT)/obj/ETC/sepolicy_intermediates \
+	$(PRODUCT_OUT)/obj/ETC/init.environ.rc_intermediates
 
 # The files/dirs to delete during a dataclean, which removes any files
 # in the staging and emulator data partitions.
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index 64aabda..ff20255 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -23,6 +23,7 @@
 LOCAL_OVERRIDES_PACKAGES:=
 LOCAL_EXPORT_PACKAGE_RESOURCES:=
 LOCAL_MANIFEST_PACKAGE_NAME:=
+LOCAL_PACKAGE_SPLITS:=
 LOCAL_REQUIRED_MODULES:=
 LOCAL_ACP_UNAVAILABLE:=
 LOCAL_MODULE_TAGS:=
@@ -96,6 +97,7 @@
 LOCAL_JAR_MANIFEST:=
 LOCAL_INSTRUMENTATION_FOR:=
 LOCAL_APK_LIBRARIES:=
+LOCAL_RES_LIBRARIES:=
 LOCAL_MANIFEST_INSTRUMENTATION_FOR:=
 LOCAL_AIDL_INCLUDES:=
 LOCAL_JARJAR_RULES:=
@@ -115,6 +117,7 @@
 LOCAL_WARNINGS_ENABLE:=
 LOCAL_FULL_MANIFEST_FILE:=
 LOCAL_MANIFEST_FILE:=
+LOCAL_FULL_LIBS_MANIFEST_FILES:=
 LOCAL_RENDERSCRIPT_INCLUDES:=
 LOCAL_RENDERSCRIPT_INCLUDES_OVERRIDE:=
 LOCAL_RENDERSCRIPT_CC:=
@@ -129,6 +132,7 @@
 LOCAL_PROTO_JAVA_OUTPUT_PARAMS:=
 LOCAL_NO_CRT:=
 LOCAL_PROPRIETARY_MODULE:=
+LOCAL_OEM_MODULE:=
 LOCAL_PRIVILEGED_MODULE:=
 LOCAL_MODULE_OWNER:=
 LOCAL_CTS_TEST_PACKAGE:=
@@ -137,6 +141,7 @@
 LOCAL_ADDRESS_SANITIZER:=
 LOCAL_JAR_EXCLUDE_FILES:=
 LOCAL_JAR_PACKAGES:=
+LOCAL_JAR_EXCLUDE_PACKAGES:=
 LOCAL_LINT_FLAGS:=
 LOCAL_SOURCE_FILES_ALL_GENERATED:= # '',true
 # Don't delete the META_INF dir when merging static Java libraries.
@@ -147,6 +152,7 @@
 LOCAL_POST_INSTALL_CMD:=
 LOCAL_DIST_BUNDLED_BINARIES:=
 LOCAL_HAL_STATIC_LIBRARIES:=
+LOCAL_RMTYPEDEFS:=
 LOCAL_NO_SYNTAX_CHECK:=
 LOCAL_NO_STATIC_ANALYZER:=
 LOCAL_32_BIT_ONLY:= # '',true
diff --git a/core/combo/HOST_windows-x86.mk b/core/combo/HOST_windows-x86.mk
index 766c14a..d4acfe9 100644
--- a/core/combo/HOST_windows-x86.mk
+++ b/core/combo/HOST_windows-x86.mk
@@ -28,9 +28,14 @@
 HOST_ACP_UNAVAILABLE := true
 TOOLS_EXE_SUFFIX :=
 $(combo_2nd_arch_prefix)HOST_GLOBAL_CFLAGS += -DUSE_MINGW
-TOOLS_PREFIX := /usr/bin/i586-mingw32msvc-
-$(combo_2nd_arch_prefix)HOST_C_INCLUDES += /usr/lib/gcc/i586-mingw32msvc/3.4.4/include
-$(combo_2nd_arch_prefix)HOST_GLOBAL_LD_DIRS += -L/usr/i586-mingw32msvc/lib
+$(combo_2nd_arch_prefix)HOST_GLOBAL_CFLAGS += -Wno-unused-parameter
+$(combo_2nd_arch_prefix)HOST_GLOBAL_CFLAGS += --sysroot=prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8/x86_64-w64-mingw32
+$(combo_2nd_arch_prefix)HOST_GLOBAL_CFLAGS += -m32
+$(combo_2nd_arch_prefix)HOST_GLOBAL_LDFLAGS += -m32
+TOOLS_PREFIX := prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8/bin/x86_64-w64-mingw32-
+$(combo_2nd_arch_prefix)HOST_C_INCLUDES += prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8/x86_64-w64-mingw32/include
+$(combo_2nd_arch_prefix)HOST_C_INCLUDES += prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8/lib/gcc/x86_64-w64-mingw32/4.8.3/include
+$(combo_2nd_arch_prefix)HOST_GLOBAL_LD_DIRS += -Lprebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8/x86_64-w64-mingw32/lib32
 endif # USE_MINGW
 endif # Linux
 
diff --git a/core/combo/TARGET_linux-arm.mk b/core/combo/TARGET_linux-arm.mk
index 2d7faae..d9fbd2f 100644
--- a/core/combo/TARGET_linux-arm.mk
+++ b/core/combo/TARGET_linux-arm.mk
@@ -115,7 +115,7 @@
 # into no-op in some builds while mesg is defined earlier. So we explicitly
 # disable "-Wunused-but-set-variable" here.
 ifneq ($(filter 4.6 4.6.% 4.7 4.7.% 4.8, $($(combo_2nd_arch_prefix)TARGET_GCC_VERSION)),)
-$(combo_2nd_arch_prefix)TARGET_GLOBAL_CFLAGS += -Wno-unused-but-set-variable -fno-builtin-sin \
+$(combo_2nd_arch_prefix)TARGET_GLOBAL_CFLAGS += -fno-builtin-sin \
 			-fno-strict-volatile-bitfields
 endif
 
@@ -164,8 +164,8 @@
         $($(combo_2nd_arch_prefix)TARGET_GLOBAL_CFLAGS) -print-libgcc-file-name)
 $(combo_2nd_arch_prefix)TARGET_LIBATOMIC := $(shell $($(combo_2nd_arch_prefix)TARGET_CC) \
         $($(combo_2nd_arch_prefix)TARGET_GLOBAL_CFLAGS) -print-file-name=libatomic.a)
-$(combo_2nd_arch_prefix)TARGET_LIBGCOV := $(shell $($(combo_2nd_arch_prefix)TARGET_CC) $($(combo_2nd_arch_prefix)TARGET_GLOBAL_CFLAGS) \
-        -print-file-name=libgcov.a)
+$(combo_2nd_arch_prefix)TARGET_LIBGCOV := $(shell $($(combo_2nd_arch_prefix)TARGET_CC) \
+        $($(combo_2nd_arch_prefix)TARGET_GLOBAL_CFLAGS) -print-file-name=libgcov.a)
 endif
 
 KERNEL_HEADERS_COMMON := $(libc_root)/kernel/uapi
@@ -207,7 +207,6 @@
 	$(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
 	$(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--end-group) \
 	$(if $(TARGET_BUILD_APPS),$(PRIVATE_TARGET_LIBGCC)) \
-	$(PRIVATE_TARGET_FDO_LIB) \
 	$(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
 	-o $@ \
 	$(PRIVATE_TARGET_GLOBAL_LDFLAGS) \
@@ -235,7 +234,6 @@
 	$(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
 	$(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--end-group) \
 	$(if $(TARGET_BUILD_APPS),$(PRIVATE_TARGET_LIBGCC)) \
-	$(PRIVATE_TARGET_FDO_LIB) \
 	$(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
 	-o $@ \
 	$(PRIVATE_TARGET_GLOBAL_LDFLAGS) \
@@ -263,7 +261,6 @@
 	-Wl,--start-group \
 	$(call normalize-target-libraries,$(filter %libc.a,$(PRIVATE_ALL_STATIC_LIBRARIES))) \
 	$(call normalize-target-libraries,$(filter %libc_nomalloc.a,$(PRIVATE_ALL_STATIC_LIBRARIES))) \
-	$(PRIVATE_TARGET_FDO_LIB) \
 	$(PRIVATE_TARGET_LIBATOMIC) \
 	$(if $(filter true,$(NATIVE_COVERAGE)),$(PRIVATE_TARGET_LIBGCOV)) \
 	$(if $(PRIVATE_LIBCXX),,$(PRIVATE_TARGET_LIBGCC)) \
diff --git a/core/combo/TARGET_linux-arm64.mk b/core/combo/TARGET_linux-arm64.mk
index f0fab7b..34eb274 100644
--- a/core/combo/TARGET_linux-arm64.mk
+++ b/core/combo/TARGET_linux-arm64.mk
@@ -35,7 +35,7 @@
 endif
 
 # Decouple NDK library selection with platform compiler version
-TARGET_NDK_GCC_VERSION := 4.8
+TARGET_NDK_GCC_VERSION := 4.9
 
 ifeq ($(strip $(TARGET_GCC_VERSION_EXP)),)
 TARGET_GCC_VERSION := 4.9
@@ -173,7 +173,6 @@
 	$(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
 	$(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--end-group) \
 	$(if $(TARGET_BUILD_APPS),$(PRIVATE_TARGET_LIBGCC)) \
-	$(PRIVATE_TARGET_FDO_LIB) \
 	$(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
 	-o $@ \
 	$(PRIVATE_TARGET_GLOBAL_LDFLAGS) \
@@ -201,7 +200,6 @@
 	$(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
 	$(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--end-group) \
 	$(if $(TARGET_BUILD_APPS),$(PRIVATE_TARGET_LIBGCC)) \
-	$(PRIVATE_TARGET_FDO_LIB) \
 	$(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
 	-o $@ \
 	$(PRIVATE_TARGET_GLOBAL_LDFLAGS) \
@@ -229,7 +227,6 @@
 	-Wl,--start-group \
 	$(call normalize-target-libraries,$(filter %libc.a,$(PRIVATE_ALL_STATIC_LIBRARIES))) \
 	$(call normalize-target-libraries,$(filter %libc_nomalloc.a,$(PRIVATE_ALL_STATIC_LIBRARIES))) \
-	$(PRIVATE_TARGET_FDO_LIB) \
 	$(PRIVATE_TARGET_LIBATOMIC) \
 	$(if $(filter true,$(NATIVE_COVERAGE)),$(PRIVATE_TARGET_LIBGCOV)) \
 	$(if $(PRIVATE_LIBCXX),,$(PRIVATE_TARGET_LIBGCC)) \
diff --git a/core/combo/TARGET_linux-mips.mk b/core/combo/TARGET_linux-mips.mk
index b260073..9abee7a 100644
--- a/core/combo/TARGET_linux-mips.mk
+++ b/core/combo/TARGET_linux-mips.mk
@@ -179,7 +179,6 @@
 	$(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
 	$(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--end-group) \
 	$(if $(TARGET_BUILD_APPS),$(PRIVATE_TARGET_LIBGCC)) \
-	$(PRIVATE_TARGET_FDO_LIB) \
 	$(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
 	-o $@ \
 	$(PRIVATE_TARGET_GLOBAL_LDFLAGS) \
@@ -207,7 +206,6 @@
 	$(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
 	$(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--end-group) \
 	$(if $(TARGET_BUILD_APPS),$(PRIVATE_TARGET_LIBGCC)) \
-	$(PRIVATE_TARGET_FDO_LIB) \
 	$(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
 	-o $@ \
 	$(PRIVATE_TARGET_GLOBAL_LDFLAGS) \
@@ -235,7 +233,6 @@
 	-Wl,--start-group \
 	$(call normalize-target-libraries,$(filter %libc.a,$(PRIVATE_ALL_STATIC_LIBRARIES))) \
 	$(call normalize-target-libraries,$(filter %libc_nomalloc.a,$(PRIVATE_ALL_STATIC_LIBRARIES))) \
-	$(PRIVATE_TARGET_FDO_LIB) \
 	$(PRIVATE_TARGET_LIBATOMIC) \
 	$(if $(filter true,$(NATIVE_COVERAGE)),$(PRIVATE_TARGET_LIBGCOV)) \
 	$(if $(PRIVATE_LIBCXX),,$(PRIVATE_TARGET_LIBGCC)) \
diff --git a/core/combo/TARGET_linux-mips64.mk b/core/combo/TARGET_linux-mips64.mk
index ef66a73..2b37606 100644
--- a/core/combo/TARGET_linux-mips64.mk
+++ b/core/combo/TARGET_linux-mips64.mk
@@ -183,7 +183,6 @@
 	$(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
 	$(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--end-group) \
 	$(if $(TARGET_BUILD_APPS),$(PRIVATE_TARGET_LIBGCC)) \
-	$(PRIVATE_TARGET_FDO_LIB) \
 	$(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
 	-o $@ \
 	$(PRIVATE_TARGET_GLOBAL_LDFLAGS) \
@@ -211,7 +210,6 @@
 	$(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
 	$(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--end-group) \
 	$(if $(TARGET_BUILD_APPS),$(PRIVATE_TARGET_LIBGCC)) \
-	$(PRIVATE_TARGET_FDO_LIB) \
 	$(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
 	-o $@ \
 	$(PRIVATE_TARGET_GLOBAL_LDFLAGS) \
@@ -239,7 +237,6 @@
 	-Wl,--start-group \
 	$(call normalize-target-libraries,$(filter %libc.a,$(PRIVATE_ALL_STATIC_LIBRARIES))) \
 	$(call normalize-target-libraries,$(filter %libc_nomalloc.a,$(PRIVATE_ALL_STATIC_LIBRARIES))) \
-	$(PRIVATE_TARGET_FDO_LIB) \
 	$(PRIVATE_TARGET_LIBATOMIC) \
 	$(if $(filter true,$(NATIVE_COVERAGE)),$(PRIVATE_TARGET_LIBGCOV)) \
 	$(if $(PRIVATE_LIBCXX),,$(PRIVATE_TARGET_LIBGCC)) \
diff --git a/core/combo/TARGET_linux-x86.mk b/core/combo/TARGET_linux-x86.mk
index ef37de0..c65df54 100644
--- a/core/combo/TARGET_linux-x86.mk
+++ b/core/combo/TARGET_linux-x86.mk
@@ -160,7 +160,6 @@
 	$(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
 	$(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--end-group) \
 	$(if $(TARGET_BUILD_APPS),$(PRIVATE_TARGET_LIBGCC)) \
-	$(PRIVATE_TARGET_FDO_LIB) \
 	$(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
 	-o $@ \
 	$(PRIVATE_LDFLAGS) \
@@ -188,7 +187,6 @@
 	$(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
 	$(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--end-group) \
 	$(if $(TARGET_BUILD_APPS),$(PRIVATE_TARGET_LIBGCC)) \
-	$(PRIVATE_TARGET_FDO_LIB) \
 	$(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
 	-o $@ \
 	$(PRIVATE_LDFLAGS) \
@@ -213,7 +211,6 @@
 	-Wl,--no-whole-archive \
 	-Wl,--start-group \
 	$(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
-	$(PRIVATE_TARGET_FDO_LIB) \
 	$(PRIVATE_TARGET_LIBATOMIC) \
 	$(if $(filter true,$(NATIVE_COVERAGE)),$(PRIVATE_TARGET_LIBGCOV)) \
 	$(if $(PRIVATE_LIBCXX),,$(PRIVATE_TARGET_LIBGCC)) \
diff --git a/core/combo/TARGET_linux-x86_64.mk b/core/combo/TARGET_linux-x86_64.mk
index c7a53a6..556190e 100644
--- a/core/combo/TARGET_linux-x86_64.mk
+++ b/core/combo/TARGET_linux-x86_64.mk
@@ -165,7 +165,6 @@
 	$(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
 	$(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--end-group) \
 	$(if $(TARGET_BUILD_APPS),$(PRIVATE_TARGET_LIBGCC)) \
-	$(PRIVATE_TARGET_FDO_LIB) \
 	$(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
 	-o $@ \
 	$(PRIVATE_LDFLAGS) \
@@ -192,7 +191,6 @@
 	$(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
 	$(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--end-group) \
 	$(if $(TARGET_BUILD_APPS),$(PRIVATE_TARGET_LIBGCC)) \
-	$(PRIVATE_TARGET_FDO_LIB) \
 	$(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
 	-o $@ \
 	$(PRIVATE_LDFLAGS) \
@@ -217,7 +215,6 @@
 	-Wl,--no-whole-archive \
 	-Wl,--start-group \
 	$(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
-	$(PRIVATE_TARGET_FDO_LIB) \
 	$(PRIVATE_TARGET_LIBATOMIC) \
 	$(if $(filter true,$(NATIVE_COVERAGE)),$(PRIVATE_TARGET_LIBGCOV)) \
 	$(if $(PRIVATE_LIBCXX),,$(PRIVATE_TARGET_LIBGCC)) \
diff --git a/core/combo/fdo.mk b/core/combo/fdo.mk
index 26e842f..9e331b6 100644
--- a/core/combo/fdo.mk
+++ b/core/combo/fdo.mk
@@ -17,25 +17,23 @@
 # Setup FDO related flags.
 
 $(combo_2nd_arch_prefix)TARGET_FDO_CFLAGS:=
-$(combo_2nd_arch_prefix)TARGET_FDO_LIB:=
 
-ifneq ($(strip $(BUILD_FDO_INSTRUMENT)),)
+ifeq ($(strip $(BUILD_FDO_INSTRUMENT)), true)
   # Set BUILD_FDO_INSTRUMENT=true to turn on FDO instrumentation.
-  # The profile will be generated on /data/local/tmp/profile on the device.
-  $(combo_2nd_arch_prefix)TARGET_FDO_CFLAGS := -fprofile-generate=/data/local/tmp/fdo_profile -DANDROID_FDO
-  $(combo_2nd_arch_prefix)TARGET_FDO_LIB := $(target_libgcov)
+  # The profile will be generated on /sdcard/fdo_profile on the device.
+  $(combo_2nd_arch_prefix)TARGET_FDO_CFLAGS := -fprofile-generate=/sdcard/fdo_profile -DANDROID_FDO
+  $(combo_2nd_arch_prefix)TARGET_FDO_LDFLAGS := -lgcov -lgcc
 else
-  ifneq ($(strip $(BUILD_FDO_OPTIMIZE)),)
+  ifeq ($(strip $(BUILD_FDO_OPTIMIZE)), true)
     # Set TARGET_FDO_PROFILE_PATH to set a custom profile directory for your build.
     ifeq ($(strip $($(combo_2nd_arch_prefix)TARGET_FDO_PROFILE_PATH)),)
-      $(combo_2nd_arch_prefix)TARGET_FDO_PROFILE_PATH := fdo_profiles
+      $(combo_2nd_arch_prefix)TARGET_FDO_PROFILE_PATH := vendor/google_data/fdo_profile
     endif
 
-    ifneq ($(strip $(wildcard $($(combo_2nd_arch_prefix)TARGET_FDO_PROFILE_PATH))),)
+    ifneq ($(strip $(wildcard $($(combo_2nd_arch_prefix)TARGET_FDO_PROFILE_PATH)/$(PRODUCT_OUT))),)
       $(combo_2nd_arch_prefix)TARGET_FDO_CFLAGS := -fprofile-use=$($(combo_2nd_arch_prefix)TARGET_FDO_PROFILE_PATH) -DANDROID_FDO -fprofile-correction -Wcoverage-mismatch -Wno-error
-      $(combo_2nd_arch_prefix)TARGET_FDO_LIB := $(target_libgcov)
     else
-      $(warning Profile directory $($(combo_2nd_arch_prefix)TARGET_FDO_PROFILE_PATH) does not exist. Turn off FDO.)
+      $(warning Profile directory $($(combo_2nd_arch_prefix)TARGET_FDO_PROFILE_PATH)/$(PRODUCT_OUT) does not exist. Turn off FDO.)
     endif
   endif
 endif
diff --git a/core/config.mk b/core/config.mk
index d0743f4..bfa5610 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -18,6 +18,14 @@
 empty :=
 space := $(empty) $(empty)
 comma := ,
+# Note that make will eat the newline just before endef.
+define newline
+
+
+endef
+# Unfortunately you can't simply define backslash as \ or \\.
+backslash := \a
+backslash := $(patsubst %a,%,$(backslash))
 
 # Tell python not to spam the source tree with .pyc files.  This
 # only has an effect on python 2.6 and above.
@@ -37,13 +45,13 @@
 	$(TOPDIR)frameworks/native/include \
 	$(TOPDIR)frameworks/native/opengl/include \
 	$(TOPDIR)frameworks/av/include \
-	$(TOPDIR)frameworks/base/include \
-	$(TOPDIR)external/skia/include
+	$(TOPDIR)frameworks/base/include
 SRC_HOST_HEADERS:=$(TOPDIR)tools/include
 SRC_LIBRARIES:= $(TOPDIR)libs
 SRC_SERVERS:= $(TOPDIR)servers
 SRC_TARGET_DIR := $(TOPDIR)build/target
 SRC_API_DIR := $(TOPDIR)prebuilts/sdk/api
+SRC_SYSTEM_API_DIR := $(TOPDIR)prebuilts/sdk/system-api
 
 # Some specific paths to tools
 SRC_DROIDDOC_DIR := $(TOPDIR)build/tools/droiddoc
@@ -387,6 +395,8 @@
 MKEXT2IMG := $(HOST_OUT_EXECUTABLES)/genext2fs$(HOST_EXECUTABLE_SUFFIX)
 MAKE_EXT4FS := $(HOST_OUT_EXECUTABLES)/make_ext4fs$(HOST_EXECUTABLE_SUFFIX)
 MKEXTUSERIMG := $(HOST_OUT_EXECUTABLES)/mkuserimg.sh
+MAKE_F2FS := $(HOST_OUT_EXECUTABLES)/make_f2fs$(HOST_EXECUTABLE_SUFFIX)
+MKF2FSUSERIMG := $(HOST_OUT_EXECUTABLES)/mkf2fsuserimg.sh
 MKEXT2BOOTIMG := external/genext2fs/mkbootimg_ext2.sh
 SIMG2IMG := $(HOST_OUT_EXECUTABLES)/simg2img$(HOST_EXECUTABLE_SUFFIX)
 E2FSCK := $(HOST_OUT_EXECUTABLES)/e2fsck$(HOST_EXECUTABLE_SUFFIX)
@@ -399,6 +409,11 @@
 LLVM_RS_CC := $(HOST_OUT_EXECUTABLES)/llvm-rs-cc$(HOST_EXECUTABLE_SUFFIX)
 BCC_COMPAT := $(HOST_OUT_EXECUTABLES)/bcc_compat$(HOST_EXECUTABLE_SUFFIX)
 LINT := prebuilts/sdk/tools/lint
+RMTYPEDEFS := $(HOST_OUT_EXECUTABLES)/rmtypedefs
+APPEND2SIMG := $(HOST_OUT_EXECUTABLES)/append2simg
+VERITY_SIGNER := $(HOST_OUT_EXECUTABLES)/verity_signer
+BUILD_VERITY_TREE := $(HOST_OUT_EXECUTABLES)/build_verity_tree
+BOOT_SIGNER := $(HOST_OUT_EXECUTABLES)/boot_signer
 
 # ACP is always for the build OS, not for the host OS
 ACP := $(BUILD_OUT_EXECUTABLES)/acp$(BUILD_EXECUTABLE_SUFFIX)
@@ -406,9 +421,13 @@
 # dx is java behind a shell script; no .exe necessary.
 DX := $(HOST_OUT_EXECUTABLES)/dx
 ZIPALIGN := $(HOST_OUT_EXECUTABLES)/zipalign$(HOST_EXECUTABLE_SUFFIX)
-FINDBUGS := prebuilt/common/findbugs/bin/findbugs
+FINDBUGS_DIR := external/owasp/sanitizer/tools/findbugs/bin
+FINDBUGS := $(FINDBUGS_DIR)/findbugs
 EMMA_JAR := external/emma/lib/emma$(COMMON_JAVA_PACKAGE_SUFFIX)
 
+# Tool to merge AndroidManifest.xmls
+ANDROID_MANIFEST_MERGER := java -classpath prebuilts/devtools/tools/lib/manifest-merger.jar com.android.manifmerger.Main merge
+
 YACC_HEADER_SUFFIX:= .hpp
 
 # Don't use column under Windows, cygwin or not
@@ -523,7 +542,7 @@
 
 # allow overriding default Java libraries on a per-target basis
 ifeq ($(TARGET_DEFAULT_JAVA_LIBRARIES),)
-  TARGET_DEFAULT_JAVA_LIBRARIES := core-libart core-junit ext framework framework2
+  TARGET_DEFAULT_JAVA_LIBRARIES := core-libart core-junit ext framework
 endif
 
 TARGET_CPU_SMP ?= true
@@ -576,7 +595,13 @@
     $(patsubst $(HISTORICAL_SDK_VERSIONS_ROOT)/%/android.jar,%, \
     $(wildcard $(HISTORICAL_SDK_VERSIONS_ROOT)/*/android.jar)))
 
+# We don't have prebuilt system_current SDK yet.
+TARGET_AVAILABLE_SDK_VERSIONS := $(TARGET_AVAILABLE_SDK_VERSIONS)
+
 INTERNAL_PLATFORM_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/public_api.txt
+INTERNAL_PLATFORM_REMOVED_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/removed.txt
+INTERNAL_PLATFORM_SYSTEM_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/system-api.txt
+INTERNAL_PLATFORM_SYSTEM_REMOVED_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/system-removed.txt
 
 # This is the standard way to name a directory containing prebuilt target
 # objects. E.g., prebuilt/$(TARGET_PREBUILT_TAG)/libc.so
diff --git a/core/definitions.mk b/core/definitions.mk
index afd033a..1007f33 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -1423,6 +1423,10 @@
 HOST_FPIE_FLAGS :=
 else
 HOST_FPIE_FLAGS := -pie
+# Force the correct entry point to workaround a bug in binutils that manifests with -pie
+ifeq ($(HOST_OS),windows)
+HOST_FPIE_FLAGS += -Wl,-e_mainCRTStartup
+endif
 endif
 
 ifneq ($(HOST_CUSTOM_LD_COMMAND),true)
@@ -1576,7 +1580,7 @@
 $(call unzip-jar-files,$(PRIVATE_STATIC_JAVA_LIBRARIES),$(PRIVATE_CLASS_INTERMEDIATES_DIR))
 $(call dump-words-to-file,$(PRIVATE_JAVA_SOURCES),$(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list)
 $(hide) if [ -d "$(PRIVATE_SOURCE_INTERMEDIATES_DIR)" ]; then \
-	    find $(PRIVATE_SOURCE_INTERMEDIATES_DIR) -name '*.java' >> $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list; \
+          find $(PRIVATE_SOURCE_INTERMEDIATES_DIR) -name '*.java' >> $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list; \
 fi
 $(hide) tr ' ' '\n' < $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list \
     | sort -u > $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq
@@ -1601,12 +1605,21 @@
     -name $(word 1, $(PRIVATE_JAR_EXCLUDE_FILES)) \
     $(addprefix -o -name , $(wordlist 2, 999, $(PRIVATE_JAR_EXCLUDE_FILES))) \
     | xargs rm -rf)
-$(if $(PRIVATE_JAR_PACKAGES), $(hide) find $(PRIVATE_CLASS_INTERMEDIATES_DIR) -mindepth 1 -type d \
-    $(foreach pkg, $(PRIVATE_JAR_PACKAGES), \
-        -not -path $(PRIVATE_CLASS_INTERMEDIATES_DIR)/$(subst .,/,$(pkg))) \
-    | xargs rm -rf)
-$(hide) jar $(if $(strip $(PRIVATE_JAR_MANIFEST)),-cfm,-cf) \
-    $@ $(PRIVATE_JAR_MANIFEST) -C $(PRIVATE_CLASS_INTERMEDIATES_DIR) .
+$(if $(PRIVATE_JAR_PACKAGES), \
+    $(hide) find $(PRIVATE_CLASS_INTERMEDIATES_DIR) -mindepth 1 -type f \
+        $(foreach pkg, $(PRIVATE_JAR_PACKAGES), \
+            -not -path $(PRIVATE_CLASS_INTERMEDIATES_DIR)/$(subst .,/,$(pkg))/\*) -delete ; \
+        find $(PRIVATE_CLASS_INTERMEDIATES_DIR) -empty -delete)
+$(if $(PRIVATE_JAR_EXCLUDE_PACKAGES), $(hide) rm -rf \
+    $(foreach pkg, $(PRIVATE_JAR_EXCLUDE_PACKAGES), \
+        $(PRIVATE_CLASS_INTERMEDIATES_DIR)/$(subst .,/,$(pkg))))
+$(if $(PRIVATE_RMTYPEDEFS), $(hide) $(RMTYPEDEFS) -v $(PRIVATE_CLASS_INTERMEDIATES_DIR))
+$(if $(PRIVATE_JAR_MANIFEST), \
+    $(hide) sed -e 's/%BUILD_NUMBER%/$(BUILD_NUMBER)/' \
+            $(PRIVATE_JAR_MANIFEST) > $(dir $@)/manifest.mf && \
+        jar -cfm $@ $(dir $@)/manifest.mf \
+            -C $(PRIVATE_CLASS_INTERMEDIATES_DIR) ., \
+    $(hide) jar -cf $@ -C $(PRIVATE_CLASS_INTERMEDIATES_DIR) .)
 endef
 
 define transform-java-to-classes.jar
@@ -1652,12 +1665,21 @@
     -name $(word 1, $(PRIVATE_JAR_EXCLUDE_FILES)) \
     $(addprefix -o -name , $(wordlist 2, 999, $(PRIVATE_JAR_EXCLUDE_FILES))) \
     | xargs rm -rf)
-$(if $(PRIVATE_JAR_PACKAGES), $(hide) find $(PRIVATE_CLASS_INTERMEDIATES_DIR) -mindepth 1 -type d \
-    $(foreach pkg, $(PRIVATE_JAR_PACKAGES), \
-        -not -path $(PRIVATE_CLASS_INTERMEDIATES_DIR)/$(subst .,/,$(pkg))) \
-    | xargs rm -rf)
-$(hide) jar $(if $(strip $(PRIVATE_JAR_MANIFEST)),-cfm,-cf) \
-    $@ $(PRIVATE_JAR_MANIFEST) -C $(PRIVATE_CLASS_INTERMEDIATES_DIR) .
+$(if $(PRIVATE_JAR_PACKAGES), \
+    $(hide) find $(PRIVATE_CLASS_INTERMEDIATES_DIR) -mindepth 1 -type f \
+        $(foreach pkg, $(PRIVATE_JAR_PACKAGES), \
+            -not -path $(PRIVATE_CLASS_INTERMEDIATES_DIR)/$(subst .,/,$(pkg))/\*) -delete ; \
+        find $(PRIVATE_CLASS_INTERMEDIATES_DIR) -empty -delete)
+$(if $(PRIVATE_JAR_EXCLUDE_PACKAGES), $(hide) rm -rf \
+    $(foreach pkg, $(PRIVATE_JAR_EXCLUDE_PACKAGES), \
+        $(PRIVATE_CLASS_INTERMEDIATES_DIR)/$(subst .,/,$(pkg))))
+$(if $(PRIVATE_RMTYPEDEFS), $(hide) $(RMTYPEDEFS) -v $(PRIVATE_CLASS_INTERMEDIATES_DIR))
+$(if $(PRIVATE_JAR_MANIFEST), \
+    $(hide) sed -e 's/%BUILD_NUMBER%/$(BUILD_NUMBER)/' \
+            $(PRIVATE_JAR_MANIFEST) > $(dir $@)/manifest.mf && \
+        jar -cfm $@ $(dir $@)/manifest.mf \
+            -C $(PRIVATE_CLASS_INTERMEDIATES_DIR) ., \
+    $(hide) jar -cf $@ -C $(PRIVATE_CLASS_INTERMEDIATES_DIR) .)
 $(hide) mv $(PRIVATE_CLASS_INTERMEDIATES_DIR)/newstamp $(PRIVATE_CLASS_INTERMEDIATES_DIR)/stamp
 endef
 
@@ -1679,7 +1701,7 @@
 define transform-classes.jar-to-dex
 @echo "target Dex: $(PRIVATE_MODULE)"
 @mkdir -p $(dir $@)
-$(hide) rm -f $(dir $@)/classes*.dex
+$(hide) rm -f $(dir $@)classes*.dex
 $(hide) $(DX) \
     $(if $(findstring windows,$(HOST_OS)),,-JXms16M -JXmx2048M) \
     --dex --output=$(dir $@) \
@@ -1717,7 +1739,7 @@
 define add-assets-to-package
 $(hide) $(AAPT) package -u $(PRIVATE_AAPT_FLAGS) \
     $(addprefix -c , $(PRIVATE_PRODUCT_AAPT_CONFIG)) \
-    $(addprefix --preferred-configurations , $(PRIVATE_PRODUCT_AAPT_PREF_CONFIG)) \
+    $(addprefix --preferred-density , $(PRIVATE_PRODUCT_AAPT_PREF_CONFIG)) \
     $(addprefix -M , $(PRIVATE_ANDROID_MANIFEST)) \
     $(addprefix -S , $(PRIVATE_RESOURCE_DIR)) \
     $(addprefix -A , $(PRIVATE_ASSET_DIR)) \
@@ -1752,7 +1774,7 @@
 
 #TODO: update the manifest to point to the dex file
 define add-dex-to-package
-$(hide) zip -qj $@ $(dir $(PRIVATE_DEX_FILE))/classes*.dex
+$(hide) zip -qj $@ $(dir $(PRIVATE_DEX_FILE))classes*.dex
 endef
 
 # Add java resources added by the current module.
@@ -2001,8 +2023,8 @@
 endef
 
 # $(1): The file(s) to check (often $@)
-# $(2): The maximum total image size, in decimal bytes
-# $(3): the type of filesystem "yaffs" or "raw"
+# $(2): The maximum total image size, in decimal bytes.
+#    Make sure to take into account any reserved space needed for the FS.
 #
 # If $(2) is empty, evaluates to "true"
 #
@@ -2015,15 +2037,9 @@
   total=$$(( $$( echo "$$size" ) )); \
   printname=$$(echo -n "$(1)" | tr " " +); \
   img_blocksize=$(call image-size-from-data-size,$(BOARD_FLASH_BLOCK_SIZE)); \
-  if [ "$(3)" == "yaffs" ]; then \
-    reservedblocks=8; \
-  else \
-    reservedblocks=0; \
-  fi; \
   twoblocks=$$((img_blocksize * 2)); \
   onepct=$$((((($(2) / 100) - 1) / img_blocksize + 1) * img_blocksize)); \
-  reserve=$$(((twoblocks > onepct ? twoblocks : onepct) + \
-               reservedblocks * img_blocksize)); \
+  reserve=$$((twoblocks > onepct ? twoblocks : onepct)); \
   maxsize=$$(($(2) - reserve)); \
   echo "$$printname maxsize=$$maxsize blocksize=$$img_blocksize total=$$total reserve=$$reserve"; \
   if [ "$$total" -gt "$$maxsize" ]; then \
@@ -2045,8 +2061,7 @@
 # $(2): The partition size.
 define assert-max-image-size
 $(if $(2), \
-  $(call assert-max-file-size,$(1),$(call image-size-from-data-size,$(2))), \
-  true)
+  $(call assert-max-file-size,$(1),$(call image-size-from-data-size,$(2))))
 endef
 
 
@@ -2145,17 +2160,19 @@
 #    $(1)  target
 #    $(2)  stable api file
 #    $(3)  api file to be tested
-#    $(4)  arguments for apicheck
-#    $(5)  command to run if apicheck failed
-#    $(6)  target dependent on this api check
-#    $(7)  additional dependencies
+#    $(4)  stable removed api file
+#    $(5)  removed api file to be tested
+#    $(6)  arguments for apicheck
+#    $(7)  command to run if apicheck failed
+#    $(8)  target dependent on this api check
+#    $(9)  additional dependencies
 define check-api
-$(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/$(strip $(1))-timestamp: $(2) $(3) $(APICHECK) $(7)
+$(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/$(strip $(1))-timestamp: $(2) $(3) $(4) $(APICHECK) $(9)
 	@echo "Checking API:" $(1)
-	$(hide) ( $(APICHECK_COMMAND) $(4) $(2) $(3) || ( $(5) ; exit 38 ) )
+	$(hide) ( $(APICHECK_COMMAND) $(6) $(2) $(3) $(4) $(5) || ( $(7) ; exit 38 ) )
 	$(hide) mkdir -p $$(dir $$@)
 	$(hide) touch $$@
-$(6): $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/$(strip $(1))-timestamp
+$(8): $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/$(strip $(1))-timestamp
 endef
 
 ## Whether to build from source if prebuilt alternative exists
@@ -2182,11 +2199,13 @@
 $(if $(call if-build-from-source,$(2),$(3)),$(eval include $(1)))
 endef
 
-## Return the arch for the source file of a prebuilt
+# Return the arch for the source file of a prebuilt
+# Return "none" if no matching arch found, so the result can be passed to
+# LOCAL_MODULE_TARGET_ARCH.
 # $(1) the list of archs supported by the prebuilt
 define get-prebuilt-src-arch
 $(strip $(if $(filter $(TARGET_ARCH),$(1)),$(TARGET_ARCH),\
-  $(if $(filter $(TARGET_2ND_ARCH),$(1)),$(TARGET_2ND_ARCH))))
+  $(if $(filter $(TARGET_2ND_ARCH),$(1)),$(TARGET_2ND_ARCH),none)))
 endef
 
 ###########################################################
diff --git a/core/dex_preopt.mk b/core/dex_preopt.mk
index 02e812d..72cb9f0 100644
--- a/core/dex_preopt.mk
+++ b/core/dex_preopt.mk
@@ -10,6 +10,8 @@
 DEXPREOPT_BOOT_JARS_MODULES := $(PRODUCT_BOOT_JARS)
 PRODUCT_BOOTCLASSPATH := $(subst $(space),:,$(foreach m,$(DEXPREOPT_BOOT_JARS_MODULES),/system/framework/$(m).jar))
 
+PRODUCT_SYSTEM_SERVER_CLASSPATH := $(subst $(space),:,$(foreach m,$(PRODUCT_SYSTEM_SERVER_JARS),/system/framework/$(m).jar))
+
 DEXPREOPT_BUILD_DIR := $(OUT_DIR)
 DEXPREOPT_PRODUCT_DIR_FULL_PATH := $(PRODUCT_OUT)/dex_bootjars
 DEXPREOPT_PRODUCT_DIR := $(patsubst $(DEXPREOPT_BUILD_DIR)/%,%,$(DEXPREOPT_PRODUCT_DIR_FULL_PATH))
diff --git a/core/droiddoc.mk b/core/droiddoc.mk
index ecfe3dc..d3e61d5 100644
--- a/core/droiddoc.mk
+++ b/core/droiddoc.mk
@@ -64,12 +64,15 @@
     # Use android_stubs_current if LOCAL_SDK_VERSION is current and no TARGET_BUILD_APPS.
     LOCAL_JAVA_LIBRARIES := android_stubs_current $(LOCAL_JAVA_LIBRARIES)
     $(full_target): PRIVATE_BOOTCLASSPATH := $(call java-lib-files, android_stubs_current)
+  else ifeq ($(LOCAL_SDK_VERSION)$(TARGET_BUILD_APPS),system_current)
+    LOCAL_JAVA_LIBRARIES := android_system_stubs_current $(LOCAL_JAVA_LIBRARIES)
+    $(full_target): PRIVATE_BOOTCLASSPATH := $(call java-lib-files, android_system_stubs_current)
   else
     LOCAL_JAVA_LIBRARIES := sdk_v$(LOCAL_SDK_VERSION) $(LOCAL_JAVA_LIBRARIES)
     $(full_target): PRIVATE_BOOTCLASSPATH := $(call java-lib-files, sdk_v$(LOCAL_SDK_VERSION))
   endif
 else
-  LOCAL_JAVA_LIBRARIES := core-libart ext framework framework2 $(LOCAL_JAVA_LIBRARIES)
+  LOCAL_JAVA_LIBRARIES := core-libart ext framework $(LOCAL_JAVA_LIBRARIES)
   $(full_target): PRIVATE_BOOTCLASSPATH := $(call java-lib-files, core-libart)
 endif  # LOCAL_SDK_VERSION
 LOCAL_JAVA_LIBRARIES := $(sort $(LOCAL_JAVA_LIBRARIES))
@@ -134,15 +137,13 @@
 $(full_target): PRIVATE_IN_CUSTOM_ASSET_DIR := $(LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR)/$(LOCAL_DROIDDOC_CUSTOM_ASSET_DIR)
 $(full_target): PRIVATE_OUT_ASSET_DIR := $(out_dir)/$(LOCAL_DROIDDOC_ASSET_DIR)
 $(full_target): PRIVATE_OUT_CUSTOM_ASSET_DIR := $(out_dir)/$(LOCAL_DROIDDOC_CUSTOM_ASSET_DIR)
+
+html_dir_files :=
 ifneq ($(strip $(LOCAL_DROIDDOC_HTML_DIR)),)
 $(full_target): PRIVATE_DROIDDOC_HTML_DIR := -htmldir $(LOCAL_PATH)/$(LOCAL_DROIDDOC_HTML_DIR)
+html_dir_files := $(shell find $(LOCAL_PATH)/$(LOCAL_DROIDDOC_HTML_DIR) -type f)
 else
-$(full_target): PRIVATE_DROIDDOC_HTML_DIR := 
-endif
-ifneq ($(strip $(LOCAL_ADDITIONAL_HTML_DIR)),)
-$(full_target): PRIVATE_ADDITIONAL_HTML_DIR := -htmldir2 $(LOCAL_PATH)/$(LOCAL_ADDITIONAL_HTML_DIR)
-else
-$(full_target): PRIVATE_ADDITIONAL_HTML_DIR :=
+$(full_target): PRIVATE_DROIDDOC_HTML_DIR :=
 endif
 ifneq ($(strip $(LOCAL_ADDITIONAL_HTML_DIR)),)
 $(full_target): PRIVATE_ADDITIONAL_HTML_DIR := -htmldir2 $(LOCAL_PATH)/$(LOCAL_ADDITIONAL_HTML_DIR)
@@ -153,8 +154,6 @@
 # TODO: not clear if this is used any more
 $(full_target): PRIVATE_LOCAL_PATH := $(LOCAL_PATH)
 
-html_dir_files := $(shell find $(LOCAL_PATH)/$(LOCAL_DROIDDOC_HTML_DIR) -type f)
-
 $(full_target): $(full_src_files) $(droiddoc_templates) $(droiddoc) $(html_dir_files) $(full_java_lib_deps) $(LOCAL_ADDITIONAL_DEPENDENCIES)
 	@echo Docs droiddoc: $(PRIVATE_OUT_DIR)
 	$(hide) mkdir -p $(dir $@)
diff --git a/core/dynamic_binary.mk b/core/dynamic_binary.mk
index 396199c..3d6ad4a 100644
--- a/core/dynamic_binary.mk
+++ b/core/dynamic_binary.mk
@@ -110,6 +110,15 @@
 $(strip_output): PRIVATE_READELF := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_READELF)
 $(strip_output): $(strip_input) | $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_STRIP)
 	$(transform-to-stripped-keep-symbols)
+
+# A product may be configured to strip everything in some build variants.
+# We do the stripping as a post-install command so that LOCAL_BUILT_MODULE
+# is still with the symbols and we don't need to clean it (and relink) when
+# you switch build variant.
+ifneq ($(filter $(STRIP_EVERYTHING_BUILD_VARIANTS),$(TARGET_BUILD_VARIANT)),)
+$(LOCAL_INSTALLED_MODULE): PRIVATE_POST_INSTALL_CMD := \
+  $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_STRIP) --strip-all $(LOCAL_INSTALLED_MODULE)
+endif
 else
 # Don't strip the binary, just copy it.  We can't skip this step
 # because a copy of the binary must appear at LOCAL_BUILT_MODULE.
diff --git a/core/envsetup.mk b/core/envsetup.mk
index efcad0d..cfc9650 100644
--- a/core/envsetup.mk
+++ b/core/envsetup.mk
@@ -106,11 +106,21 @@
 # Define them here so they can be used in product config files.
 TARGET_COPY_OUT_SYSTEM := system
 TARGET_COPY_OUT_DATA := data
-TARGET_COPY_OUT_VENDOR := system/vendor
+TARGET_COPY_OUT_OEM := oem
 TARGET_COPY_OUT_ROOT := root
 TARGET_COPY_OUT_RECOVERY := recovery
+###########################################
+# Define TARGET_COPY_OUT_VENDOR to a placeholder, for at this point
+# we don't know if the device wants to build a separate vendor.img
+# or just build vendor stuff into system.img.
+# A device can set up TARGET_COPY_OUT_VENDOR to "vendor" in its
+# BoardConfig.mk.
+# We'll substitute with the real value after loading BoardConfig.mk.
+_vendor_path_placeholder := ||VENDOR-PATH-PH||
+TARGET_COPY_OUT_VENDOR := $(_vendor_path_placeholder)
+###########################################
 
-# Read the product specs so we an get TARGET_DEVICE and other
+# Read the product specs so we can get TARGET_DEVICE and other
 # variables that we need in order to locate the output files.
 include $(BUILD_SYSTEM)/product_config.mk
 
@@ -154,6 +164,17 @@
 TARGET_DEVICE_DIR := $(patsubst %/,%,$(dir $(board_config_mk)))
 board_config_mk :=
 
+###########################################
+# Now we can substitute with the real value of TARGET_COPY_OUT_VENDOR
+ifeq ($(TARGET_COPY_OUT_VENDOR),$(_vendor_path_placeholder))
+TARGET_COPY_OUT_VENDOR := system/vendor
+else ifeq ($(filter vendor system/vendor,$(TARGET_COPY_OUT_VENDOR)),)
+$(error TARGET_COPY_OUT_VENDOR must be either 'vendor' or 'system/vendor', seeing '$(TARGET_COPY_OUT_VENDOR)'.)
+endif
+PRODUCT_COPY_FILES := $(subst $(_vendor_path_placeholder),$(TARGET_COPY_OUT_VENDOR),$(PRODUCT_COPY_FILES))
+###########################################
+
+
 # ---------------------------------------------------------------
 # Set up configuration for target machine.
 # The following must be set:
@@ -222,6 +243,7 @@
 HOST_OUT_INTERMEDIATE_LIBRARIES := $(HOST_OUT_INTERMEDIATES)/lib
 HOST_OUT_NOTICE_FILES := $(HOST_OUT_INTERMEDIATES)/NOTICE_FILES
 HOST_OUT_COMMON_INTERMEDIATES := $(HOST_COMMON_OUT_ROOT)/obj
+HOST_OUT_FAKE := $(HOST_OUT)/fake_packages
 
 HOST_OUT_GEN := $(HOST_OUT)/gen
 HOST_OUT_COMMON_GEN := $(HOST_COMMON_OUT_ROOT)/gen
@@ -317,9 +339,26 @@
 $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_VENDOR_SHARED_LIBRARIES := $(TARGET_OUT_VENDOR)/lib
 $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_VENDOR_APPS := $(TARGET_OUT_VENDOR_APPS)
 
+TARGET_OUT_OEM := $(PRODUCT_OUT)/$(TARGET_COPY_OUT_OEM)
+TARGET_OUT_OEM_EXECUTABLES := $(TARGET_OUT_OEM)/bin
+ifneq ($(filter %64,$(TARGET_ARCH)),)
+TARGET_OUT_OEM_SHARED_LIBRARIES := $(TARGET_OUT_OEM)/lib64
+else
+TARGET_OUT_OEM_SHARED_LIBRARIES := $(TARGET_OUT_OEM)/lib
+endif
+# We don't expect Java libraries in the oem.img.
+# TARGET_OUT_OEM_JAVA_LIBRARIES:= $(TARGET_OUT_OEM)/framework
+TARGET_OUT_OEM_APPS := $(TARGET_OUT_OEM)/app
+TARGET_OUT_OEM_ETC := $(TARGET_OUT_OEM)/etc
+
+$(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_OEM_EXECUTABLES := $(TARGET_OUT_OEM_EXECUTABLES)
+$(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_OEM_SHARED_LIBRARIES := $(TARGET_OUT_OEM)/lib
+$(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_OEM_APPS := $(TARGET_OUT_OEM_APPS)
+
 TARGET_OUT_UNSTRIPPED := $(PRODUCT_OUT)/symbols
 TARGET_OUT_EXECUTABLES_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/system/bin
 TARGET_OUT_SHARED_LIBRARIES_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/system/lib
+TARGET_OUT_VENDOR_SHARED_LIBRARIES_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/$(TARGET_COPY_OUT_VENDOR)/lib
 TARGET_ROOT_OUT_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)
 TARGET_ROOT_OUT_SBIN_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/sbin
 TARGET_ROOT_OUT_BIN_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/bin
diff --git a/core/executable_internal.mk b/core/executable_internal.mk
index 2655dd1..ebb6867 100644
--- a/core/executable_internal.mk
+++ b/core/executable_internal.mk
@@ -35,7 +35,6 @@
 
 # Define PRIVATE_ variables from global vars
 my_target_global_ld_dirs := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_GLOBAL_LD_DIRS)
-my_target_fdo_lib := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_FDO_LIB)
 my_target_libgcov := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_LIBGCOV)
 my_target_libgcc := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_LIBGCC)
 my_target_libatomic := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_LIBATOMIC)
@@ -56,7 +55,6 @@
 endif
 $(linked_module): PRIVATE_TARGET_GLOBAL_LD_DIRS := $(my_target_global_ld_dirs)
 $(linked_module): PRIVATE_TARGET_GLOBAL_LDFLAGS := $(my_target_global_ldflags)
-$(linked_module): PRIVATE_TARGET_FDO_LIB := $(my_target_fdo_lib)
 $(linked_module): PRIVATE_TARGET_LIBGCOV := $(my_target_libgcov)
 $(linked_module): PRIVATE_TARGET_LIBGCC := $(my_target_libgcc)
 $(linked_module): PRIVATE_TARGET_LIBATOMIC := $(my_target_libatomic)
diff --git a/core/executable_prefer_symlink.mk b/core/executable_prefer_symlink.mk
index f66a5f2..2326e83 100644
--- a/core/executable_prefer_symlink.mk
+++ b/core/executable_prefer_symlink.mk
@@ -8,17 +8,27 @@
 # configuration. Note that we require the TARGET_IS_64_BIT
 # check because 32 bit targets may not define TARGET_PREFER_32_BIT_APPS
 # et al. since those variables make no sense in that context.
-
 ifneq ($(LOCAL_IS_HOST_MODULE),true)
   my_symlink := $(addprefix $(TARGET_OUT)/bin/, $(LOCAL_MODULE))
   ifeq ($(TARGET_IS_64_BIT),true)
-    ifneq ($(TARGET_PREFER_32_BIT_APPS),true)
-$(my_symlink): PRIVATE_SRC_BINARY_NAME := $(LOCAL_MODULE_STEM_64)
+    ifeq ($(TARGET_SUPPORTS_64_BIT_APPS)|$(TARGET_SUPPORTS_32_BIT_APPS),true|true)
+      # We support both 32 and 64 bit apps, so we will have to
+      # base our decision on whether the target prefers one or the
+      # other.
+      ifeq ($(TARGET_PREFER_32_BIT_APPS),true)
+        $(my_symlink): PRIVATE_SRC_BINARY_NAME := $(LOCAL_MODULE_STEM_32)
+      else
+        $(my_symlink): PRIVATE_SRC_BINARY_NAME := $(LOCAL_MODULE_STEM_64)
+      endif
+    else ifeq ($(TARGET_SUPPORTS_64_BIT_APPS),true)
+      # We support only 64 bit apps.
+      $(my_symlink): PRIVATE_SRC_BINARY_NAME := $(LOCAL_MODULE_STEM_64)
     else
-$(my_symlink): PRIVATE_SRC_BINARY_NAME := $(LOCAL_MODULE_STEM_32)
+      # We support only 32 bit apps.
+      $(my_symlink): PRIVATE_SRC_BINARY_NAME := $(LOCAL_MODULE_STEM_32)
     endif
   else
-$(my_symlink): PRIVATE_SRC_BINARY_NAME := $(LOCAL_MODULE_STEM_32)
+    $(my_symlink): PRIVATE_SRC_BINARY_NAME := $(LOCAL_MODULE_STEM_32)
   endif
 else
   my_symlink := $(addprefix $(HOST_OUT)/bin/, $(LOCAL_MODULE))
diff --git a/core/host_dalvik_java_library.mk b/core/host_dalvik_java_library.mk
index e15bde2..61eb3ff 100644
--- a/core/host_dalvik_java_library.mk
+++ b/core/host_dalvik_java_library.mk
@@ -67,6 +67,7 @@
 $(full_classes_compiled_jar): PRIVATE_JAVACFLAGS := $(LOCAL_JAVACFLAGS)
 $(full_classes_compiled_jar): PRIVATE_JAR_EXCLUDE_FILES :=
 $(full_classes_compiled_jar): PRIVATE_JAR_PACKAGES :=
+$(full_classes_compiled_jar): PRIVATE_JAR_EXCLUDE_PACKAGES :=
 $(full_classes_compiled_jar): PRIVATE_RMTYPEDEFS :=
 $(full_classes_compiled_jar): $(java_sources) $(java_resource_sources) $(full_java_lib_deps) \
         $(jar_manifest_file) $(proto_java_sources_file_stamp) $(LOCAL_ADDITIONAL_DEPENDENCIES)
diff --git a/core/host_java_library.mk b/core/host_java_library.mk
index e5ebb11..7e0e437 100644
--- a/core/host_java_library.mk
+++ b/core/host_java_library.mk
@@ -20,21 +20,65 @@
 
 #######################################
 include $(BUILD_SYSTEM)/host_java_library_common.mk
+#######################################
+
+# Enable emma instrumentation only if the module asks so.
+ifeq (true,$(LOCAL_EMMA_INSTRUMENT))
+ifneq (true,$(EMMA_INSTRUMENT))
+LOCAL_EMMA_INSTRUMENT :=
+endif
+endif
+
+full_classes_compiled_jar := $(intermediates.COMMON)/classes-full-debug.jar
+emma_intermediates_dir := $(intermediates.COMMON)/emma_out
+# emma is hardcoded to use the leaf name of its input for the output file --
+# only the output directory can be changed
+full_classes_emma_jar := $(emma_intermediates_dir)/lib/$(notdir $(full_classes_compiled_jar))
+
+LOCAL_INTERMEDIATE_TARGETS += \
+    $(full_classes_compiled_jar) \
+    $(full_classes_emma_jar)
+
+#######################################
 include $(BUILD_SYSTEM)/base_rules.mk
 #######################################
 
-$(full_classes_compiled_jar): PRIVATE_JAVAC_DEBUG_FLAGS := -g
+ifeq (true,$(LOCAL_EMMA_INSTRUMENT))
+$(full_classes_emma_jar): PRIVATE_EMMA_COVERAGE_FILE := $(intermediates.COMMON)/coverage.em
+$(full_classes_emma_jar): PRIVATE_EMMA_INTERMEDIATES_DIR := $(emma_intermediates_dir)
+ifdef LOCAL_EMMA_COVERAGE_FILTER
+$(full_classes_emma_jar): PRIVATE_EMMA_COVERAGE_FILTER := $(LOCAL_EMMA_COVERAGE_FILTER)
+else
+# by default, avoid applying emma instrumentation onto emma classes itself,
+# otherwise there will be exceptions thrown
+$(full_classes_emma_jar): PRIVATE_EMMA_COVERAGE_FILTER := *,-emma,-emmarun,-com.vladium.*
+endif
+# this rule will generate both $(PRIVATE_EMMA_COVERAGE_FILE) and
+# $(full_classes_emma_jar)
+$(full_classes_emma_jar) : $(full_classes_compiled_jar) | $(EMMA_JAR)
+	$(transform-classes.jar-to-emma)
 
-java_alternative_checked_module :=
+$(LOCAL_BUILT_MODULE) : $(full_classes_emma_jar)
+	@echo Copying: $@
+	$(hide) $(ACP) -fp $< $@
+
+else # LOCAL_EMMA_INSTRUMENT
+# Directly build into LOCAL_BUILT_MODULE.
+full_classes_compiled_jar := $(LOCAL_BUILT_MODULE)
+endif # LOCAL_EMMA_INSTRUMENT
+
+$(full_classes_compiled_jar): PRIVATE_JAVAC_DEBUG_FLAGS := -g
 
 # The layers file allows you to enforce a layering between java packages.
 # Run build/tools/java-layers.py for more details.
 layers_file := $(addprefix $(LOCAL_PATH)/, $(LOCAL_JAVA_LAYERS_FILE))
 
-$(LOCAL_BUILT_MODULE): PRIVATE_JAVA_LAYERS_FILE := $(layers_file)
-$(LOCAL_BUILT_MODULE): PRIVATE_JAVACFLAGS := $(LOCAL_JAVACFLAGS)
-$(LOCAL_BUILT_MODULE): PRIVATE_JAR_EXCLUDE_FILES :=
-$(LOCAL_BUILT_MODULE): PRIVATE_JAVA_LAYERS_FILE := $(layers_file)
-$(LOCAL_BUILT_MODULE): $(java_sources) $(java_resource_sources) $(full_java_lib_deps) \
+$(full_classes_compiled_jar): PRIVATE_JAVA_LAYERS_FILE := $(layers_file)
+$(full_classes_compiled_jar): PRIVATE_JAVACFLAGS := $(LOCAL_JAVACFLAGS)
+$(full_classes_compiled_jar): PRIVATE_JAR_EXCLUDE_FILES :=
+$(full_classes_compiled_jar): PRIVATE_JAR_PACKAGES :=
+$(full_classes_compiled_jar): PRIVATE_JAR_EXCLUDE_PACKAGES :=
+$(full_classes_compiled_jar): PRIVATE_RMTYPEDEFS :=
+$(full_classes_compiled_jar): $(java_sources) $(java_resource_sources) $(full_java_lib_deps) \
 		$(jar_manifest_file) $(proto_java_sources_file_stamp) $(LOCAL_ADDITIONAL_DEPENDENCIES)
 	$(transform-host-java-to-package)
diff --git a/core/install_jni_libs_internal.mk b/core/install_jni_libs_internal.mk
index eb90c50..944420b 100644
--- a/core/install_jni_libs_internal.mk
+++ b/core/install_jni_libs_internal.mk
@@ -18,7 +18,7 @@
           $(LOCAL_JNI_SHARED_LIBRARIES)))
 
 # App-specific lib path.
-my_app_lib_path :=  $($(my_2nd_arch_prefix)TARGET_OUT$(partition_tag)_SHARED_LIBRARIES)/$(basename $(my_installed_module_stem))
+my_app_lib_path := $(dir $(LOCAL_INSTALLED_MODULE))lib/$(TARGET_$(my_2nd_arch_prefix)ARCH)
 my_extracted_jni_libs :=
 
 ifdef my_embed_jni
@@ -54,16 +54,20 @@
 # The jni libaries will be installed to the system.img.
 my_jni_filenames := $(notdir $(my_jni_shared_libraries))
 # Make sure the JNI libraries get installed
-$(LOCAL_INSTALLED_MODULE) : | $(addprefix $($(my_2nd_arch_prefix)TARGET_OUT$(partition_tag)_SHARED_LIBRARIES)/, $(my_jni_filenames))
+my_shared_library_path := $($(my_2nd_arch_prefix)TARGET_OUT$(partition_tag)_SHARED_LIBRARIES)
+$(LOCAL_INSTALLED_MODULE) : | $(addprefix $(my_shared_library_path)/, $(my_jni_filenames))
 
 # Create symlink in the app specific lib path
 ifdef LOCAL_POST_INSTALL_CMD
 # Add a shell command separator
 LOCAL_POST_INSTALL_CMD += ;
 endif
+
+my_symlink_target_dir := $(patsubst $(PRODUCT_OUT)%,%,\
+    $(my_shared_library_path))
 LOCAL_POST_INSTALL_CMD += \
   mkdir -p $(my_app_lib_path) \
-  $(foreach lib, $(my_jni_filenames), ;ln -sf ../$(lib) $(my_app_lib_path)/$(lib))
+  $(foreach lib, $(my_jni_filenames), ;ln -sf $(my_symlink_target_dir)/$(lib) $(my_app_lib_path)/$(lib))
 $(LOCAL_INSTALLED_MODULE): PRIVATE_POST_INSTALL_CMD := $(LOCAL_POST_INSTALL_CMD)
 
 # Clear jni_shared_libraries to not embed it into the apk.
diff --git a/core/java.mk b/core/java.mk
index 049bc51..debdf53 100644
--- a/core/java.mk
+++ b/core/java.mk
@@ -26,6 +26,8 @@
       ifeq ($(LOCAL_SDK_VERSION)$(TARGET_BUILD_APPS),current)
         # Use android_stubs_current if LOCAL_SDK_VERSION is current and no TARGET_BUILD_APPS.
         LOCAL_JAVA_LIBRARIES := android_stubs_current $(LOCAL_JAVA_LIBRARIES)
+      else ifeq ($(LOCAL_SDK_VERSION)$(TARGET_BUILD_APPS),system_current)
+        LOCAL_JAVA_LIBRARIES := android_system_stubs_current $(LOCAL_JAVA_LIBRARIES)
       else
         LOCAL_JAVA_LIBRARIES := sdk_v$(LOCAL_SDK_VERSION) $(LOCAL_JAVA_LIBRARIES)
       endif
@@ -142,7 +144,7 @@
 else
 ifneq (,$(LOCAL_SDK_VERSION))
 # Set target-api for LOCAL_SDK_VERSIONs other than current.
-ifneq (,$(filter-out current, $(LOCAL_SDK_VERSION)))
+ifneq (,$(filter-out current system_current, $(LOCAL_SDK_VERSION)))
 renderscript_target_api := $(LOCAL_SDK_VERSION)
 endif
 endif  # LOCAL_SDK_VERSION is set
@@ -158,7 +160,7 @@
 renderscript_flags += $(LOCAL_RENDERSCRIPT_FLAGS)
 
 # prepend the RenderScript system include path
-ifneq ($(filter-out current,$(LOCAL_SDK_VERSION))$(if $(TARGET_BUILD_APPS),$(filter current,$(LOCAL_SDK_VERSION))),)
+ifneq ($(filter-out current system_current,$(LOCAL_SDK_VERSION))$(if $(TARGET_BUILD_APPS),$(filter current system_current,$(LOCAL_SDK_VERSION))),)
 # if a numeric LOCAL_SDK_VERSION, or current LOCAL_SDK_VERSION with TARGET_BUILD_APPS
 LOCAL_RENDERSCRIPT_INCLUDES := \
     $(HISTORICAL_SDK_VERSIONS_ROOT)/renderscript/clang-include \
@@ -321,6 +323,10 @@
 $(full_classes_compiled_jar): PRIVATE_JAVA_LAYERS_FILE := $(layers_file)
 $(full_classes_compiled_jar): PRIVATE_WARNINGS_ENABLE := $(LOCAL_WARNINGS_ENABLE)
 
+ifdef LOCAL_RMTYPEDEFS
+$(full_classes_compiled_jar): | $(RMTYPEDEFS)
+endif
+
 # Compile the java files to a .jar file.
 # This intentionally depends on java_sources, not all_java_sources.
 # Deps for generated source files must be handled separately,
@@ -328,6 +334,8 @@
 $(full_classes_compiled_jar): PRIVATE_JAVACFLAGS := $(LOCAL_JAVACFLAGS)
 $(full_classes_compiled_jar): PRIVATE_JAR_EXCLUDE_FILES := $(LOCAL_JAR_EXCLUDE_FILES)
 $(full_classes_compiled_jar): PRIVATE_JAR_PACKAGES := $(LOCAL_JAR_PACKAGES)
+$(full_classes_compiled_jar): PRIVATE_JAR_EXCLUDE_PACKAGES := $(LOCAL_JAR_EXCLUDE_PACKAGES)
+$(full_classes_compiled_jar): PRIVATE_RMTYPEDEFS := $(LOCAL_RMTYPEDEFS)
 $(full_classes_compiled_jar): PRIVATE_DONT_DELETE_JAR_META_INF := $(LOCAL_DONT_DELETE_JAR_META_INF)
 $(full_classes_compiled_jar): $(java_sources) $(java_resource_sources) $(full_java_lib_deps) \
         $(jar_manifest_file) $(layers_file) $(RenderScript_file_stamp) \
@@ -378,7 +386,7 @@
 
 # Run proguard if necessary, otherwise just copy the file.
 ifdef LOCAL_PROGUARD_ENABLED
-ifneq ($(filter-out full custom nosystem obfuscation optimization,$(LOCAL_PROGUARD_ENABLED)),)
+ifneq ($(filter-out full custom nosystem obfuscation optimization shrinktests,$(LOCAL_PROGUARD_ENABLED)),)
     $(warning while processing: $(LOCAL_MODULE))
     $(error invalid value for LOCAL_PROGUARD_ENABLED: $(LOCAL_PROGUARD_ENABLED))
 endif
@@ -395,6 +403,9 @@
 # If this is a test package, add proguard keep flags for tests.
 ifneq ($(LOCAL_INSTRUMENTATION_FOR)$(filter tests,$(LOCAL_MODULE_TAGS)),)
 proguard_flags += -include $(BUILD_SYSTEM)/proguard_tests.flags
+ifeq ($(filter shrinktests,$(LOCAL_PROGUARD_ENABLED)),)
+proguard_flags += -dontshrink # don't shrink tests by default
+endif # shrinktests
 endif # test package
 ifeq ($(filter obfuscation,$(LOCAL_PROGUARD_ENABLED)),)
 # By default no obfuscation
@@ -499,7 +510,7 @@
 $(findbugs_html) : $(findbugs_xml)
 	@mkdir -p $(dir $@)
 	@echo ConvertXmlToText: $@
-	$(hide) prebuilt/common/findbugs/bin/convertXmlToText -html:fancy.xsl $(PRIVATE_XML_FILE) \
+	$(hide) $(FINDBUGS_DIR)/convertXmlToText -html:fancy.xsl $(PRIVATE_XML_FILE) \
 	> $@
 
 $(LOCAL_MODULE)-findbugs : $(findbugs_html)
diff --git a/core/main.mk b/core/main.mk
index 1958a16..7ca30c7 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -185,12 +185,8 @@
 # java version is really openjdk
 ifeq ($(shell echo '$(java_version_str)' | grep -i openjdk),)
 $(info ************************************************************)
-$(info You are attempting to build with an unsupported JDK.)
-$(info $(space))
-$(info This build requires OpenJDK, but you are using:)
+$(info You asked for an OpenJDK 7 build but your version is)
 $(info $(java_version_str).)
-$(info Please follow the machine setup instructions at)
-$(info $(space)$(space)$(space)$(space)https://source.android.com/source/download.html)
 $(info ************************************************************)
 $(error stop)
 endif # java version is not OpenJdk
@@ -381,10 +377,12 @@
           $(call collapse-pairs, $(ADDITIONAL_BUILD_PROPERTIES))) \
           ro.setupwizard.mode=OPTIONAL
 endif
-# Don't even verify the image on eng builds to speed startup
-ADDITIONAL_BUILD_PROPERTIES += dalvik.vm.image-dex2oat-filter=verify-none
-# Don't compile apps on eng builds to speed startup
-ADDITIONAL_BUILD_PROPERTIES += dalvik.vm.dex2oat-filter=interpret-only
+ifndef is_sdk_build
+  # Don't even verify the image on eng builds to speed startup
+  ADDITIONAL_BUILD_PROPERTIES += dalvik.vm.image-dex2oat-filter=verify-none
+  # Don't compile apps on eng builds to speed startup
+  ADDITIONAL_BUILD_PROPERTIES += dalvik.vm.dex2oat-filter=interpret-only
+endif
 endif
 
 ## sdk ##
@@ -395,7 +393,7 @@
 sdk_repo_goal := $(strip $(filter sdk_repo,$(MAKECMDGOALS)))
 MAKECMDGOALS := $(strip $(filter-out sdk_repo,$(MAKECMDGOALS)))
 
-ifneq ($(words $(filter-out $(INTERNAL_MODIFIER_TARGETS) checkbuild,$(MAKECMDGOALS))),1)
+ifneq ($(words $(filter-out $(INTERNAL_MODIFIER_TARGETS) checkbuild emulator_tests target-files-package,$(MAKECMDGOALS))),1)
 $(error The 'sdk' target may not be specified with any other targets)
 endif
 
@@ -773,7 +771,7 @@
     $(if $(strip $(ALL_MODULES.$(m).INSTALLED) $(ALL_MODULES.$(m)$(TARGET_2ND_ARCH_MODULE_SUFFIX).INSTALLED)),,\
       $(eval dangling_modules += $(m))))
   ifneq ($(dangling_modules),)
-    $(warning Module names '$(dangling_modules)' in PRODUCT_PACKAGES has nothing to install!)
+    $(warning: Modules '$(dangling_modules)' in PRODUCT_PACKAGES have nothing to install!)
   endif
   $(foreach m, $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGES_DEBUG), \
     $(if $(strip $(ALL_MODULES.$(m).INSTALLED)),,\
@@ -965,6 +963,7 @@
   $(foreach f,$(INSTALLED_RADIOIMAGE_TARGET), \
     $(call dist-for-goals, droidcore, $(f)))
 
+  ifneq ($(ANDROID_BUILD_EMBEDDED),true)
   ifneq ($(TARGET_BUILD_PDK),true)
     $(call dist-for-goals, droidcore, \
       $(APPS_ZIP) \
@@ -972,6 +971,7 @@
       $(PACKAGE_STATS_FILE) \
     )
   endif
+  endif
 
   ifeq ($(EMMA_INSTRUMENT),true)
     $(EMMA_META_ZIP) : $(INSTALLED_SYSTEMIMAGE)
@@ -1011,6 +1011,12 @@
 target-native-tests : native-target-tests
 tests : host-tests target-tests
 
+# To catch more build breakage, check build tests modules in eng and userdebug builds.
+ifneq ($(TARGET_BUILD_PDK),true)
+ifneq ($(filter eng userdebug,$(TARGET_BUILD_VARIANT)),)
+droidcore : target-tests host-tests
+endif
+endif
 
 .PHONY: lintall
 
@@ -1035,7 +1041,7 @@
 
 .PHONY: clean
 clean:
-	@rm -rf $(OUT_DIR)
+	@rm -rf $(OUT_DIR)/*
 	@echo "Entire build directory removed."
 
 .PHONY: clobber
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/package_internal.mk b/core/package_internal.mk
index a951357..bb458d4 100644
--- a/core/package_internal.mk
+++ b/core/package_internal.mk
@@ -52,16 +52,6 @@
 endif
 LOCAL_MODULE := $(LOCAL_PACKAGE_NAME)
 
-ifeq ($(strip $(LOCAL_MANIFEST_FILE)),)
-LOCAL_MANIFEST_FILE := AndroidManifest.xml
-endif
-
-# If you need to put the MANIFEST_FILE outside of LOCAL_PATH
-# you can use FULL_MANIFEST_FILE
-ifeq ($(strip $(LOCAL_FULL_MANIFEST_FILE)),)
-LOCAL_FULL_MANIFEST_FILE := $(LOCAL_PATH)/$(LOCAL_MANIFEST_FILE)
-endif
-
 ifneq ($(strip $(LOCAL_MODULE_CLASS)),)
 $(error $(LOCAL_PATH): Package modules may not set LOCAL_MODULE_CLASS)
 endif
@@ -78,6 +68,10 @@
 LOCAL_AAPT_FLAGS := $(LOCAL_AAPT_FLAGS) -z
 endif
 
+ifdef LOCAL_PACKAGE_SPLITS
+LOCAL_AAPT_FLAGS += $(addprefix --split ,$(LOCAL_PACKAGE_SPLITS))
+endif
+
 need_compile_asset :=
 ifeq (,$(LOCAL_ASSET_DIR))
 LOCAL_ASSET_DIR := $(LOCAL_PATH)/assets
@@ -101,8 +95,14 @@
 
 LOCAL_RESOURCE_DIR := $(package_resource_overlays) $(LOCAL_RESOURCE_DIR)
 
-all_assets := $(call find-subdir-assets,$(LOCAL_ASSET_DIR))
-all_assets := $(addprefix $(LOCAL_ASSET_DIR)/,$(patsubst assets/%,%,$(all_assets)))
+all_assets := $(strip \
+    $(foreach dir, $(LOCAL_ASSET_DIR), \
+      $(addprefix $(dir)/, \
+        $(patsubst assets/%,%, \
+          $(call find-subdir-assets, $(dir)) \
+         ) \
+       ) \
+     ))
 
 ifneq ($(all_assets),)
 need_compile_asset := true
@@ -141,6 +141,7 @@
 endif
 
 LOCAL_BUILT_MODULE_STEM := package.apk
+LOCAL_INSTALLED_MODULE_STEM := $(LOCAL_MODULE).apk
 
 LOCAL_PROGUARD_ENABLED:=$(strip $(LOCAL_PROGUARD_ENABLED))
 ifndef LOCAL_PROGUARD_ENABLED
@@ -200,10 +201,11 @@
   LOCAL_SDK_RES_VERSION:=$(LOCAL_SDK_VERSION)
 endif
 
-full_android_manifest := $(LOCAL_FULL_MANIFEST_FILE)
+include $(BUILD_SYSTEM)/android_manifest.mk
+
 $(LOCAL_INTERMEDIATE_TARGETS): \
     PRIVATE_ANDROID_MANIFEST := $(full_android_manifest)
-ifneq (,$(filter-out current, $(LOCAL_SDK_VERSION)))
+ifneq (,$(filter-out current system_current, $(LOCAL_SDK_VERSION)))
 $(LOCAL_INTERMEDIATE_TARGETS): \
     PRIVATE_DEFAULT_APP_TARGET_SDK := $(LOCAL_SDK_VERSION)
 else
@@ -251,6 +253,7 @@
 
 $(proguard_options_file): $(R_file_stamp)
 
+resource_export_package :=
 ifdef LOCAL_EXPORT_PACKAGE_RESOURCES
 # Put this module's resources into a PRODUCT-agnositc package that
 # other packages can use to build their own PRODUCT-agnostic R.java (etc.)
@@ -290,7 +293,7 @@
 # Most packages should link against the resources defined by framework-res.
 # Even if they don't have their own resources, they may use framework
 # resources.
-ifneq ($(filter-out current,$(LOCAL_SDK_RES_VERSION))$(if $(TARGET_BUILD_APPS),$(filter current,$(LOCAL_SDK_RES_VERSION))),)
+ifneq ($(filter-out current system_current,$(LOCAL_SDK_RES_VERSION))$(if $(TARGET_BUILD_APPS),$(filter current system_current,$(LOCAL_SDK_RES_VERSION))),)
 # for released sdk versions, the platform resources were built into android.jar.
 framework_res_package_export := \
     $(HISTORICAL_SDK_VERSIONS_ROOT)/$(LOCAL_SDK_RES_VERSION)/android.jar
@@ -304,9 +307,19 @@
 framework_res_package_export_deps := \
     $(dir $(framework_res_package_export))src/R.stamp
 endif # LOCAL_SDK_RES_VERSION
-$(R_file_stamp): $(framework_res_package_export_deps)
+all_library_res_package_exports := \
+    $(framework_res_package_export) \
+    $(foreach lib,$(LOCAL_RES_LIBRARIES),\
+        $(call intermediates-dir-for,APPS,$(lib),,COMMON)/package-export.apk)
+
+all_library_res_package_export_deps := \
+    $(framework_res_package_export_deps) \
+    $(foreach lib,$(LOCAL_RES_LIBRARIES),\
+        $(call intermediates-dir-for,APPS,$(lib),,COMMON)/src/R.stamp)
+
+$(resource_export_package) $(R_file_stamp) $(LOCAL_BUILT_MODULE): $(all_library_res_package_export_deps)
 $(LOCAL_INTERMEDIATE_TARGETS): \
-    PRIVATE_AAPT_INCLUDES := $(framework_res_package_export)
+    PRIVATE_AAPT_INCLUDES := $(all_library_res_package_exports)
 endif # LOCAL_NO_STANDARD_LIBRARIES
 
 ifneq ($(full_classes_jar),)
@@ -364,8 +377,12 @@
     $(LOCAL_BUILT_MODULE): PRIVATE_PRODUCT_AAPT_PREF_CONFIG :=
 else
     $(LOCAL_BUILT_MODULE): PRIVATE_PRODUCT_AAPT_CONFIG := $(PRODUCT_AAPT_CONFIG)
+ifdef LOCAL_PACKAGE_SPLITS
+    $(LOCAL_BUILT_MODULE): PRIVATE_PRODUCT_AAPT_PREF_CONFIG :=
+else
     $(LOCAL_BUILT_MODULE): PRIVATE_PRODUCT_AAPT_PREF_CONFIG := $(PRODUCT_AAPT_PREF_CONFIG)
 endif
+endif
 $(LOCAL_BUILT_MODULE): $(all_res_assets) $(jni_shared_libraries) $(full_android_manifest)
 	@echo "target Package: $(PRIVATE_MODULE) ($@)"
 	$(create-empty-package)
@@ -402,6 +419,44 @@
 	$(hide) rm $@.input
 endif
 
+###############################
+## APK splits
+ifdef LOCAL_PACKAGE_SPLITS
+# LOCAL_PACKAGE_SPLITS is a list of resource labels.
+# aapt will convert comma inside resource lable to underscore in the file names.
+my_split_suffixes := $(subst $(comma),_,$(LOCAL_PACKAGE_SPLITS))
+built_apk_splits := $(foreach s,$(my_split_suffixes),$(built_module_path)/package_$(s).apk)
+installed_apk_splits := $(foreach s,$(my_split_suffixes),$(my_module_path)/$(LOCAL_MODULE)_$(s).apk)
+
+# The splits should have been built in the same command building the base apk.
+# This rule just runs signing and zipalign etc.
+# Note that we explicily check the existence of the split apk and remove the
+# built base apk if the split apk isn't there.
+# That way the build system will rerun the aapt after the user changes the splitting parameters.
+$(built_apk_splits): PRIVATE_PRIVATE_KEY := $(private_key)
+$(built_apk_splits): PRIVATE_CERTIFICATE := $(certificate)
+$(built_apk_splits) : $(built_module_path)/%.apk : $(LOCAL_BUILT_MODULE)
+	$(hide) if [ ! -f $@ ]; then \
+	  echo 'No $@ generated, check your apk splitting parameters.' 1>&2; \
+	  rm $<; exit 1; \
+	fi
+	$(sign-package)
+	$(align-package)
+
+# Rules to install the splits
+$(installed_apk_splits) : $(my_module_path)/$(LOCAL_MODULE)_%.apk : $(built_module_path)/package_%.apk | $(ACP)
+	@echo "Install: $@"
+	$(copy-file-to-new-target)
+
+# Register the additional built and installed files.
+ALL_MODULES.$(my_register_name).INSTALLED += $(installed_apk_splits)
+ALL_MODULES.$(my_register_name).BUILT_INSTALLED += \
+  $(foreach s,$(my_split_suffixes),$(built_module_path)/package_$(s).apk:$(my_module_path)/$(LOCAL_MODULE)_$(s).apk)
+
+# Make sure to install the splits when you run "make <module_name>".
+$(my_register_name): $(installed_apk_splits)
+endif # LOCAL_PACKAGE_SPLITS
+
 # Save information about this package
 PACKAGES.$(LOCAL_PACKAGE_NAME).OVERRIDES := $(strip $(LOCAL_OVERRIDES_PACKAGES))
 PACKAGES.$(LOCAL_PACKAGE_NAME).RESOURCE_FILES := $(all_resources)
diff --git a/core/pathmap.mk b/core/pathmap.mk
index b2abc07..0820885 100644
--- a/core/pathmap.mk
+++ b/core/pathmap.mk
@@ -29,10 +29,8 @@
 pathmap_INCL := \
     bootloader:bootable/bootloader/legacy/include \
     camera:system/media/camera/include \
-    corecg:external/skia/include/core \
     frameworks-base:frameworks/base/include \
     frameworks-native:frameworks/native/include \
-    graphics:external/skia/include/core \
     libc:bionic/libc/include \
     libhardware:hardware/libhardware/include \
     libhardware_legacy:hardware/libhardware_legacy/include \
@@ -51,6 +49,7 @@
     audio-route:system/media/audio_route/include \
     wilhelm:frameworks/wilhelm/include \
     wilhelm-ut:frameworks/wilhelm/src/ut \
+    mediandk:frameworks/av/media/ndk/ \
     speex:external/speex/include
 
 #
@@ -86,7 +85,9 @@
 	    drm \
 	    opengl \
 	    sax \
+	    telecomm \
 	    telephony \
+	    phone \
 	    wifi \
 	    keystore \
 	    rs \
@@ -105,12 +106,17 @@
 # A list of all source roots under frameworks/support.
 #
 FRAMEWORKS_SUPPORT_SUBDIRS := \
+        annotations \
         v4 \
         v7/gridlayout \
         v7/appcompat \
+        v7/cardview \
         v7/mediarouter \
+        v7/palette \
+        v7/recyclerview \
         v8/renderscript \
-        v13
+        v13 \
+        v17/leanback
 
 #
 # A list of all source roots under frameworks/multidex.
diff --git a/core/pdk_config.mk b/core/pdk_config.mk
index 9590d70..838754f 100644
--- a/core/pdk_config.mk
+++ b/core/pdk_config.mk
@@ -18,9 +18,14 @@
 
 # if PDK_FUSION_PLATFORM_ZIP is specified, do not override.
 ifndef PDK_FUSION_PLATFORM_ZIP
+# Most PDK project paths should be using vendor/pdk/TARGET_DEVICE
+# but some legacy ones (e.g. mini_armv7a_neon generic PDK) were setup
+# with vendor/pdk/TARGET_PRODUCT.
 _pdk_fusion_default_platform_zip = $(wildcard \
 vendor/pdk/$(TARGET_DEVICE)/$(TARGET_PRODUCT)-$(TARGET_BUILD_VARIANT)/platform/platform.zip \
-vendor/pdk/$(TARGET_DEVICE)/$(patsubst aosp_%,full_%,$(TARGET_PRODUCT))-$(TARGET_BUILD_VARIANT)/platform/platform.zip)
+vendor/pdk/$(TARGET_DEVICE)/$(patsubst aosp_%,full_%,$(TARGET_PRODUCT))-$(TARGET_BUILD_VARIANT)/platform/platform.zip \
+vendor/pdk/$(TARGET_PRODUCT)/$(TARGET_PRODUCT)-$(TARGET_BUILD_VARIANT)/platform/platform.zip \
+vendor/pdk/$(TARGET_PRODUCT)/$(patsubst aosp_%,full_%,$(TARGET_PRODUCT))-$(TARGET_BUILD_VARIANT)/platform/platform.zip)
 ifneq (,$(_pdk_fusion_default_platform_zip))
 PDK_FUSION_PLATFORM_ZIP := $(word 1, $(_pdk_fusion_default_platform_zip))
 TARGET_BUILD_PDK := true
@@ -37,29 +42,41 @@
 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-libart_intermediates \
 	target/common/obj/JAVA_LIBRARIES/core-junit_intermediates \
 	target/common/obj/JAVA_LIBRARIES/ext_intermediates \
 	target/common/obj/JAVA_LIBRARIES/framework_intermediates \
-	target/common/obj/JAVA_LIBRARIES/framework2_intermediates \
 	target/common/obj/JAVA_LIBRARIES/android.test.runner_intermediates \
 	target/common/obj/JAVA_LIBRARIES/telephony-common_intermediates \
 	target/common/obj/JAVA_LIBRARIES/voip-common_intermediates \
+	target/common/obj/JAVA_LIBRARIES/ims-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 +134,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 +159,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 $< $@
@@ -170,12 +192,16 @@
 ifneq (,$(filter platform platform-java, $(MAKECMDGOALS))$(filter true,$(TARGET_BUILD_PDK)))
 # files under $(PRODUCT_OUT)/symbols to help debugging.
 # Source not included to PDK due to dependency issue, so provide symbols instead.
+
+# We may not be building all of them.
+# The platform.zip just silently ignores the nonexistent ones.
 PDK_SYMBOL_FILES_LIST := \
-	system/bin/app_process
+    system/bin/app_process32 \
+    system/bin/app_process64
 
 ifdef PDK_FUSION_PLATFORM_ZIP
 # symbols should be explicitly pulled for fusion build
-$(foreach f,$(PDK_SYMBOL_FILES_LIST),\
+$(foreach f,$(filter $(PDK_SYMBOL_FILES_LIST), $(_pdk_fusion_file_list)),\
   $(eval $(call add-dependency,$(PRODUCT_OUT)/$(f),$(PRODUCT_OUT)/symbols/$(f))))
 endif # PLATFORM_ZIP
 endif # platform.zip build or PDK
diff --git a/core/post_clean.mk b/core/post_clean.mk
index 213c43c..0273ff2 100644
--- a/core/post_clean.mk
+++ b/core/post_clean.mk
@@ -15,6 +15,7 @@
 # Clean steps that need global knowledge of individual modules.
 # This file must be included after all Android.mks have been loaded.
 
+#######################################################
 # Checks the current build configurations against the previous build,
 # clean artifacts in TARGET_COMMON_OUT_ROOT if necessary.
 # If a package's resource overlay has been changed, its R class needs to be
@@ -51,3 +52,45 @@
 previous_package_overlay_config :=
 current_package_overlay_config :=
 current_all_packages_config :=
+
+#######################################################
+# Check if we need to delete obsolete aidl-generated java files.
+# When an aidl file gets deleted (or renamed), the generated java file is obsolete.
+previous_aidl_config := $(TARGET_OUT_COMMON_INTERMEDIATES)/previous_aidl_config.mk
+current_aidl_config := $(TARGET_OUT_COMMON_INTERMEDIATES)/current_aidl_config.mk
+
+$(shell rm -rf $(current_aidl_config) \
+  && mkdir -p $(dir $(current_aidl_config))\
+  && touch $(current_aidl_config))
+-include $(previous_aidl_config)
+
+intermediates_to_clean :=
+modules_with_aidl_files :=
+$(foreach p, $(ALL_MODULES), \
+  $(if $(ALL_MODULES.$(p).AIDL_FILES),\
+    $(eval modules_with_aidl_files += $(p))\
+    $(shell echo 'AIDL_FILES.$(p) := $(ALL_MODULES.$(p).AIDL_FILES)' >> $(current_aidl_config)))\
+  $(if $(filter-out $(ALL_MODULES.$(p).AIDL_FILES),$(AIDL_FILES.$(p))),\
+    $(eval intermediates_to_clean += $(ALL_MODULES.$(p).INTERMEDIATE_SOURCE_DIR))))
+intermediates_to_clean := $(strip $(intermediates_to_clean))
+ifdef intermediates_to_clean
+$(info *** Obsolete aidl-generated files detected, clean intermediate files...)
+$(info *** rm -rf $(intermediates_to_clean))
+$(shell rm -rf $(intermediates_to_clean))
+intermediates_to_clean :=
+endif
+
+# For modules not loaded by the current build (e.g. you are running mm/mmm),
+# we copy the info from the previous bulid.
+$(foreach p, $(filter-out $(ALL_MODULES),$(MODULES_WITH_AIDL_FILES)),\
+  $(shell echo 'AIDL_FILES.$(p) := $(AIDL_FILES.$(p))' >> $(current_aidl_config)))
+MODULES_WITH_AIDL_FILES := $(sort $(MODULES_WITH_AIDL_FILES) $(modules_with_aidl_files))
+$(shell echo 'MODULES_WITH_AIDL_FILES := $(MODULES_WITH_AIDL_FILES)' >> $(current_aidl_config))
+
+# Now current becomes previous.
+$(shell mv -f $(current_aidl_config) $(previous_aidl_config))
+
+MODULES_WITH_AIDL_FILES :=
+modules_with_aidl_files :=
+previous_aidl_config :=
+current_aidl_config :=
diff --git a/core/prebuilt_internal.mk b/core/prebuilt_internal.mk
index d852541..7e1ea4b 100644
--- a/core/prebuilt_internal.mk
+++ b/core/prebuilt_internal.mk
@@ -54,6 +54,11 @@
 endif
 endif
 
+ifeq ($(LOCAL_MODULE_CLASS),APPS)
+LOCAL_BUILT_MODULE_STEM := package.apk
+LOCAL_INSTALLED_MODULE_STEM := $(LOCAL_MODULE).apk
+endif
+
 ifeq ($(LOCAL_STRIP_MODULE),true)
   ifdef LOCAL_IS_HOST_MODULE
     $(error Cannot strip host module LOCAL_PATH=$(LOCAL_PATH))
@@ -109,6 +114,7 @@
 
 endif  # LOCAL_STRIP_MODULE not true
 
+ifeq ($(LOCAL_MODULE_CLASS),APPS)
 PACKAGES.$(LOCAL_MODULE).OVERRIDES := $(strip $(LOCAL_OVERRIDES_PACKAGES))
 
 rs_compatibility_jni_libs :=
@@ -128,11 +134,9 @@
   $(built_module) : PRIVATE_CERTIFICATE := $(LOCAL_CERTIFICATE).x509.pem
 endif
 ifeq ($(LOCAL_CERTIFICATE),)
-  ifneq ($(filter APPS,$(LOCAL_MODULE_CLASS)),)
-    # It is now a build error to add a prebuilt .apk without
-    # specifying a key for it.
-    $(error No LOCAL_CERTIFICATE specified for prebuilt "$(my_prebuilt_src_file)")
-  endif
+  # It is now a build error to add a prebuilt .apk without
+  # specifying a key for it.
+  $(error No LOCAL_CERTIFICATE specified for prebuilt "$(my_prebuilt_src_file)")
 else ifeq ($(LOCAL_CERTIFICATE),PRESIGNED)
   # The magic string "PRESIGNED" means this package is already checked
   # signed with its release key.
@@ -156,10 +160,10 @@
   $(built_module) : PRIVATE_CERTIFICATE := $(LOCAL_CERTIFICATE).x509.pem
 endif
 
-ifneq ($(filter APPS,$(LOCAL_MODULE_CLASS)),)
-
-# Disable dex-preopt of prebuilts to save space
+# Disable dex-preopt of prebuilts to save space, if requested.
+ifeq ($(DONT_DEXPREOPT_PREBUILTS),true)
 LOCAL_DEX_PREOPT := false
+endif
 
 #######################################
 # defines built_odex along with rule to install odex
@@ -188,6 +192,42 @@
 	$(call dexpreopt-one-file,$<,$@)
 endif
 
+###############################
+## Install split apks.
+ifdef LOCAL_PACKAGE_SPLITS
+# LOCAL_PACKAGE_SPLITS is a list of apks to be installed.
+built_apk_splits := $(addprefix $(built_module_path)/,$(notdir $(LOCAL_PACKAGE_SPLITS)))
+installed_apk_splits := $(addprefix $(my_module_path)/,$(notdir $(LOCAL_PACKAGE_SPLITS)))
+
+# Rules to sign and zipalign the split apks.
+my_src_dir := $(sort $(dir $(LOCAL_PACKAGE_SPLITS)))
+ifneq (1,$(words $(my_src_dir)))
+$(error You must put all the split source apks in the same folder: $(LOCAL_PACKAGE_SPLITS))
+endif
+my_src_dir := $(LOCAL_PATH)/$(my_src_dir)
+
+$(built_apk_splits) : PRIVATE_PRIVATE_KEY := $(LOCAL_CERTIFICATE).pk8
+$(built_apk_splits) : PRIVATE_CERTIFICATE := $(LOCAL_CERTIFICATE).x509.pem
+$(built_apk_splits) : $(built_module_path)/%.apk : $(my_src_dir)/%.apk | $(ACP)
+	$(copy-file-to-new-target)
+	$(sign-package)
+	$(align-package)
+
+# Rules to install the split apks.
+$(installed_apk_splits) : $(my_module_path)/%.apk : $(built_module_path)/%.apk | $(ACP)
+	@echo "Install: $@"
+	$(copy-file-to-new-target)
+
+# Register the additional built and installed files.
+ALL_MODULES.$(my_register_name).INSTALLED += $(installed_apk_splits)
+ALL_MODULES.$(my_register_name).BUILT_INSTALLED += \
+  $(foreach s,$(LOCAL_PACKAGE_SPLITS),$(built_module_path)/$(notdir $(s)):$(my_module_path)/$(notdir $(s)))
+
+# Make sure to install the splits when you run "make <module_name>".
+$(my_register_name): $(installed_apk_splits)
+
+endif # LOCAL_PACKAGE_SPLITS
+
 else # LOCAL_MODULE_CLASS != APPS
 ifneq ($(LOCAL_PREBUILT_STRIP_COMMENTS),)
 $(built_module) : $(my_prebuilt_src_file)
diff --git a/core/product.mk b/core/product.mk
index dbf49b5..0075acd 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -86,10 +86,12 @@
     PRODUCT_PACKAGE_OVERLAYS \
     DEVICE_PACKAGE_OVERLAYS \
     PRODUCT_TAGS \
+    PRODUCT_SDK_ATREE_FILES \
     PRODUCT_SDK_ADDON_NAME \
     PRODUCT_SDK_ADDON_COPY_FILES \
     PRODUCT_SDK_ADDON_COPY_MODULES \
     PRODUCT_SDK_ADDON_DOC_MODULES \
+    PRODUCT_SDK_ADDON_SYS_IMG_SOURCE_PROP \
     PRODUCT_DEFAULT_WIFI_CHANNELS \
     PRODUCT_DEFAULT_DEV_CERTIFICATE \
     PRODUCT_RESTRICT_VENDOR_FILES \
@@ -99,6 +101,13 @@
     PRODUCT_RUNTIMES \
     PRODUCT_BOOT_JARS \
     PRODUCT_DEX_PREOPT_IMAGE_IN_DATA \
+    PRODUCT_SUPPORTS_VERITY \
+    PRODUCT_OEM_PROPERTIES \
+    PRODUCT_SYSTEM_PROPERTY_BLACKLIST \
+    PRODUCT_SYSTEM_SERVER_JARS \
+    PRODUCT_VERITY_SIGNING_KEY \
+    PRODUCT_SYSTEM_VERITY_PARTITION \
+    PRODUCT_VENDOR_VERITY_PARTITION
 
 define dump-product
 $(info ==== $(1) ====)\
@@ -210,6 +219,7 @@
 
 _product_stash_var_list := $(_product_var_list) \
 	PRODUCT_BOOTCLASSPATH \
+	PRODUCT_SYSTEM_SERVER_CLASSPATH \
 	TARGET_ARCH \
 	TARGET_ARCH_VARIANT \
 	TARGET_CPU_VARIANT \
@@ -243,11 +253,13 @@
 	BOARD_BOOTIMAGE_PARTITION_SIZE \
 	BOARD_RECOVERYIMAGE_PARTITION_SIZE \
 	BOARD_SYSTEMIMAGE_PARTITION_SIZE \
+	BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE \
 	BOARD_USERDATAIMAGE_PARTITION_SIZE \
 	BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE \
 	BOARD_CACHEIMAGE_PARTITION_SIZE \
 	BOARD_FLASH_BLOCK_SIZE \
-	BOARD_SYSTEMIMAGE_PARTITION_SIZE \
+	BOARD_VENDORIMAGE_PARTITION_SIZE \
+	BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE \
 	BOARD_INSTALLER_CMDLINE \
 
 
diff --git a/core/product_config.mk b/core/product_config.mk
index 9468362..32e351c 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -281,6 +281,7 @@
 
 # A list of module names of BOOTCLASSPATH (jar files)
 PRODUCT_BOOT_JARS := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_BOOT_JARS))
+PRODUCT_SYSTEM_SERVER_JARS := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_SERVER_JARS))
 
 # Find the device that this product maps to.
 TARGET_DEVICE := $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEVICE)
@@ -314,11 +315,13 @@
     $(if $(filter %dpi,$(PRODUCT_AAPT_CONFIG)),,mdpi))
 PRODUCT_AAPT_PREF_CONFIG := $(strip $(PRODUCT_AAPT_PREF_CONFIG))
 
-# Everyone gets nodpi assets which are density-independent.
-PRODUCT_AAPT_CONFIG += nodpi
+# Everyone gets nodpi and anydpi assets which are density-independent.
+PRODUCT_AAPT_CONFIG += nodpi anydpi
+
+# Keep a copy of the space-separated config
+PRODUCT_AAPT_CONFIG_SP := $(PRODUCT_AAPT_CONFIG)
 
 # Convert spaces to commas.
-comma := ,
 PRODUCT_AAPT_CONFIG := \
     $(subst $(space),$(comma),$(strip $(PRODUCT_AAPT_CONFIG)))
 PRODUCT_AAPT_PREF_CONFIG := \
diff --git a/core/proguard_basic_keeps.flags b/core/proguard_basic_keeps.flags
index af0e05d..4a85db0 100644
--- a/core/proguard_basic_keeps.flags
+++ b/core/proguard_basic_keeps.flags
@@ -49,12 +49,16 @@
 # -keep class * extends android.preference.Preference
 # -keep class * extends android.app.BackupAgent
 
-#-keep class * implements android.os.Parcelable {
-#  public static final android.os.Parcelable$Creator *;
-#}
+# Parcelable CREATORs must be kept for Parcelable functionality
+-keep class * implements android.os.Parcelable {
+  public static final ** CREATOR;
+}
 
 # The support library contains references to newer platform versions.
 # Don't warn about those in case this app is linking against an older
 # platform version.  We know about them, and they are safe.
 # See proguard-android.txt in the SDK package.
 -dontwarn android.support.**
+
+# Less spammy.
+-dontnote
diff --git a/core/proguard_tests.flags b/core/proguard_tests.flags
index 4481a1b..1f840bc 100644
--- a/core/proguard_tests.flags
+++ b/core/proguard_tests.flags
@@ -1,5 +1,6 @@
 # Keep everything for tests
--dontshrink
+# This flag has been moved to the makefiles and is set for tests by default.
+#-dontshrink
 
 # But we may want to obfuscate if the main app gets obfuscated.
 # This flag has been moved to the makefiles.
diff --git a/core/sdk_font.mk b/core/sdk_font.mk
new file mode 100644
index 0000000..204403d
--- /dev/null
+++ b/core/sdk_font.mk
@@ -0,0 +1,66 @@
+###############################################################################
+# Fonts shipped with the SDK need to be renamed for Java to handle them
+# properly. Hence, a special script is used to rename the fonts. We bundle all
+# the fonts that are shipped on a newer non-space-constrained device. However,
+# OpenType fonts used on these devices are not supported by Java. Their
+# replacements are added separately.
+###############################################################################
+
+
+# The script that renames the font.
+sdk_font_rename_script := frameworks/base/tools/layoutlib/rename_font/build_font_single.py
+
+# Location of the fonttools library that the above script depends on.
+fonttools_lib := external/fonttools/Lib
+
+# A temporary location to store the renamed fonts. atree picks all files in
+# this directory and bundles it with the SDK.
+SDK_FONT_TEMP := $(call intermediates-dir-for,PACKAGING,sdk-fonts,HOST,COMMON)
+
+# The font configuration files - system_fonts.xml, fallback_fonts.xml etc.
+sdk_font_config := $(wildcard frameworks/base/data/fonts/*.xml)
+sdk_font_config :=  $(addprefix $(SDK_FONT_TEMP)/, $(notdir $(sdk_font_config)))
+
+$(sdk_font_config): $(SDK_FONT_TEMP)/%.xml: \
+			frameworks/base/data/fonts/%.xml
+	$(hide) mkdir -p $(dir $@)
+	$(hide) cp -vf $< $@
+
+# List of fonts on the device that we want to ship. This is all .ttf fonts.
+sdk_fonts_device := $(filter $(TARGET_OUT)/fonts/%.ttf, $(INTERNAL_SYSTEMIMAGE_FILES))
+sdk_fonts_device := $(addprefix $(SDK_FONT_TEMP)/, $(notdir $(sdk_fonts_device)))
+
+# Macro to rename the font.
+sdk_rename_font = PYTHONPATH=$$PYTHONPATH:$(fonttools_lib) $(sdk_font_rename_script) \
+	    $1 $2
+
+# TODO: If the font file is a symlink, reuse the font renamed from the symlink
+# target.
+$(sdk_fonts_device): $(SDK_FONT_TEMP)/%.ttf: $(TARGET_OUT)/fonts/%.ttf \
+			$(sdk_font_rename_script)
+	$(hide) mkdir -p $(dir $@)
+	$(hide) $(call sdk_rename_font,$<,$@)
+
+# List of all dependencies - all fonts and configuration files.
+SDK_FONT_DEPS := $(sdk_fonts_device) $(sdk_font_config)
+
+# Define a macro to create rule for addititional fonts that we want to include
+# in the SDK.
+# $1 Output font name
+# $2 Source font path
+define sdk-extra-font-rule
+fontfullname := $$(SDK_FONT_TEMP)/$1
+ifeq ($$(filter $$(fontfullname),$$(sdk_fonts_device)),)
+SDK_FONT_DEPS += $$(fontfullname)
+$$(fontfullname): $2 $$(sdk_font_rename_script)
+	$$(hide) mkdir -p $$(dir $$@)
+	$$(hide) $$(call sdk_rename_font,$$<,$$@)
+endif
+fontfullname :=
+endef
+
+# These extra fonts are used as a replacement for OpenType fonts.
+$(eval $(call sdk-extra-font-rule,NanumGothic.ttf,external/naver-fonts/NanumGothic.ttf))
+$(eval $(call sdk-extra-font-rule,DroidSansFallback.ttf,frameworks/base/data/fonts/DroidSansFallbackFull.ttf))
+
+sdk-extra-font-rule :=
diff --git a/core/shared_library_internal.mk b/core/shared_library_internal.mk
index 29b7d44..baedb3b 100644
--- a/core/shared_library_internal.mk
+++ b/core/shared_library_internal.mk
@@ -40,7 +40,6 @@
 
 # Define PRIVATE_ variables from global vars
 my_target_global_ld_dirs := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_GLOBAL_LD_DIRS)
-my_target_fdo_lib := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_FDO_LIB)
 my_target_libgcov := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_LIBGCOV)
 my_target_libgcc := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_LIBGCC)
 my_target_libatomic := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_LIBATOMIC)
@@ -59,7 +58,6 @@
 endif
 $(linked_module): PRIVATE_TARGET_GLOBAL_LD_DIRS := $(my_target_global_ld_dirs)
 $(linked_module): PRIVATE_TARGET_GLOBAL_LDFLAGS := $(my_target_global_ldflags)
-$(linked_module): PRIVATE_TARGET_FDO_LIB := $(my_target_fdo_lib)
 $(linked_module): PRIVATE_TARGET_LIBGCOV := $(my_target_libgcov)
 $(linked_module): PRIVATE_TARGET_LIBGCC := $(my_target_libgcc)
 $(linked_module): PRIVATE_TARGET_LIBATOMIC := $(my_target_libatomic)
diff --git a/core/static_java_library.mk b/core/static_java_library.mk
index 79b7292..02078e0 100644
--- a/core/static_java_library.mk
+++ b/core/static_java_library.mk
@@ -67,14 +67,7 @@
 ifeq (true,$(need_compile_res))
 R_file_stamp := $(LOCAL_INTERMEDIATE_SOURCE_DIR)/R.stamp
 
-ifeq ($(strip $(LOCAL_MANIFEST_FILE)),)
-  LOCAL_MANIFEST_FILE := AndroidManifest.xml
-endif
-ifdef LOCAL_FULL_MANIFEST_FILE
-  full_android_manifest := $(LOCAL_FULL_MANIFEST_FILE)
-else
-  full_android_manifest := $(LOCAL_PATH)/$(LOCAL_MANIFEST_FILE)
-endif
+include $(BUILD_SYSTEM)/android_manifest.mk
 
 LOCAL_SDK_RES_VERSION:=$(strip $(LOCAL_SDK_RES_VERSION))
 ifeq ($(LOCAL_SDK_RES_VERSION),)
@@ -85,7 +78,7 @@
 framework_res_package_export_deps :=
 # Please refer to package.mk
 ifneq ($(LOCAL_NO_STANDARD_LIBRARIES),true)
-ifneq ($(filter-out current,$(LOCAL_SDK_RES_VERSION))$(if $(TARGET_BUILD_APPS),$(filter current,$(LOCAL_SDK_RES_VERSION))),)
+ifneq ($(filter-out current system_current,$(LOCAL_SDK_RES_VERSION))$(if $(TARGET_BUILD_APPS),$(filter current system_current,$(LOCAL_SDK_RES_VERSION))),)
 framework_res_package_export := \
     $(HISTORICAL_SDK_VERSIONS_ROOT)/$(LOCAL_SDK_RES_VERSION)/android.jar
 framework_res_package_export_deps := $(framework_res_package_export)
@@ -105,7 +98,7 @@
 $(R_file_stamp): PRIVATE_RESOURCE_PUBLICS_OUTPUT := $(intermediates.COMMON)/public_resources.xml
 $(R_file_stamp): PRIVATE_RESOURCE_DIR := $(LOCAL_RESOURCE_DIR)
 $(R_file_stamp): PRIVATE_AAPT_INCLUDES := $(framework_res_package_export)
-ifneq (,$(filter-out current, $(LOCAL_SDK_VERSION)))
+ifneq (,$(filter-out current system_current, $(LOCAL_SDK_VERSION)))
 $(R_file_stamp): PRIVATE_DEFAULT_APP_TARGET_SDK := $(LOCAL_SDK_VERSION)
 else
 $(R_file_stamp): PRIVATE_DEFAULT_APP_TARGET_SDK := $(DEFAULT_APP_TARGET_SDK)
diff --git a/core/tasks/apicheck.mk b/core/tasks/apicheck.mk
index 00b78b9..fc98f5b 100644
--- a/core/tasks/apicheck.mk
+++ b/core/tasks/apicheck.mk
@@ -42,6 +42,8 @@
     checkapi-last, \
     $(SRC_API_DIR)/$(last_released_sdk_version).txt, \
     $(INTERNAL_PLATFORM_API_FILE), \
+    frameworks/base/api/removed.txt, \
+    $(INTERNAL_PLATFORM_REMOVED_API_FILE), \
     -hide 2 -hide 3 -hide 4 -hide 5 -hide 6 -hide 24 -hide 25 -hide 26 -hide 27 \
     -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
     -error 16 -error 17 -error 18 , \
@@ -56,11 +58,13 @@
     checkapi-current, \
     frameworks/base/api/current.txt, \
     $(INTERNAL_PLATFORM_API_FILE), \
+    frameworks/base/api/removed.txt, \
+    $(INTERNAL_PLATFORM_REMOVED_API_FILE), \
     -error 2 -error 3 -error 4 -error 5 -error 6 \
     -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
     -error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 \
     -error 25 -error 26 -error 27, \
-    cat $(BUILD_SYSTEM)/apicheck_msg_current.txt, \
+    sed -e 's/%UPDATE_API%/update-api/g' $(BUILD_SYSTEM)/apicheck_msg_current.txt, \
     checkapi, \
     $(call doc-timestamp-for,api-stubs) \
     ))
@@ -69,5 +73,51 @@
 update-api: $(INTERNAL_PLATFORM_API_FILE) | $(ACP)
 	@echo Copying current.txt
 	$(hide) $(ACP) $(INTERNAL_PLATFORM_API_FILE) frameworks/base/api/current.txt
+	@echo Copying removed.txt
+	$(hide) $(ACP) $(INTERNAL_PLATFORM_REMOVED_API_FILE) frameworks/base/api/removed.txt
+
+
+#####################Check System API#####################
+.PHONY: checksystemapi
+
+# Check that the System API we're building hasn't broken the last-released
+# SDK version.
+$(eval $(call check-api, \
+    checksystemapi-last, \
+    $(SRC_SYSTEM_API_DIR)/$(last_released_sdk_version).txt, \
+    $(INTERNAL_PLATFORM_SYSTEM_API_FILE), \
+    frameworks/base/api/system-removed.txt, \
+    $(INTERNAL_PLATFORM_SYSTEM_REMOVED_API_FILE), \
+    -hide 2 -hide 3 -hide 4 -hide 5 -hide 6 -hide 24 -hide 25 -hide 26 -hide 27 \
+    -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
+    -error 16 -error 17 -error 18 , \
+    cat $(BUILD_SYSTEM)/apicheck_msg_last.txt, \
+    checksystemapi, \
+    $(call doc-timestamp-for,system-api-stubs) \
+    ))
+
+# Check that the System API we're building hasn't changed from the not-yet-released
+# SDK version.
+$(eval $(call check-api, \
+    checksystemapi-current, \
+    frameworks/base/api/system-current.txt, \
+    $(INTERNAL_PLATFORM_SYSTEM_API_FILE), \
+    frameworks/base/api/system-removed.txt, \
+    $(INTERNAL_PLATFORM_SYSTEM_REMOVED_API_FILE), \
+    -error 2 -error 3 -error 4 -error 5 -error 6 \
+    -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
+    -error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 \
+    -error 25 -error 26 -error 27, \
+    sed -e 's/%UPDATE_API%/update-system-api/g' $(BUILD_SYSTEM)/apicheck_msg_current.txt, \
+    checksystemapi, \
+    $(call doc-timestamp-for,system-api-stubs) \
+    ))
+
+.PHONY: update-system-api
+update-system-api: $(INTERNAL_PLATFORM_SYSTEM_API_FILE) | $(ACP)
+	@echo Copying system-current.txt
+	$(hide) $(ACP) $(INTERNAL_PLATFORM_SYSTEM_API_FILE) frameworks/base/api/system-current.txt
+	@echo Copying system-removed.txt
+	$(hide) $(ACP) $(INTERNAL_PLATFORM_SYSTEM_REMOVED_API_FILE) frameworks/base/api/system-removed.txt
 
 endif
diff --git a/core/tasks/boot_jars_package_check.mk b/core/tasks/boot_jars_package_check.mk
new file mode 100644
index 0000000..188c267
--- /dev/null
+++ b/core/tasks/boot_jars_package_check.mk
@@ -0,0 +1,46 @@
+# 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.
+
+#
+# Rules to check if classes in the boot jars are from the whitelisted packages.
+#
+
+ifneq ($(SKIP_BOOT_JARS_CHECK),true)
+ifneq ($(TARGET_BUILD_PDK),true)
+ifdef PRODUCT_BOOT_JARS
+
+intermediates := $(call intermediates-dir-for, PACKAGING, boot-jars-package-check,,COMMON)
+stamp := $(intermediates)/stamp
+built_boot_jars := $(foreach j, $(PRODUCT_BOOT_JARS), \
+  $(call intermediates-dir-for, JAVA_LIBRARIES, $(j),,COMMON)/classes.jar)
+script := build/core/tasks/check_boot_jars/check_boot_jars.py
+whitelist_file := build/core/tasks/check_boot_jars/package_whitelist.txt
+
+$(stamp): PRIVATE_BOOT_JARS := $(built_boot_jars)
+$(stamp): PRIVATE_SCRIPT := $(script)
+$(stamp): PRIVATE_WHITELIST := $(whitelist_file)
+$(stamp) : $(built_boot_jars) $(script) $(whitelist_file)
+	@echo "Check package name for $(PRIVATE_BOOT_JARS)"
+	$(hide) $(PRIVATE_SCRIPT) $(PRIVATE_WHITELIST) $(PRIVATE_BOOT_JARS)
+	$(hide) mkdir -p $(dir $@) && touch $@
+
+.PHONY: check-boot-jars
+check-boot-jars : $(stamp)
+
+# Run check-boot-jars by default
+droidcore : check-boot-jars
+
+endif  # PRODUCT_BOOT_JARS
+endif  # TARGET_BUILD_PDK not true
+endif  # SKIP_BOOT_JARS_CHECK not true
diff --git a/core/tasks/check_boot_jars/check_boot_jars.py b/core/tasks/check_boot_jars/check_boot_jars.py
new file mode 100755
index 0000000..89d9ee8
--- /dev/null
+++ b/core/tasks/check_boot_jars/check_boot_jars.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+
+"""
+Check boot jars.
+
+Usage: check_boot_jars.py <package_whitelist_file> <jar1> <jar2> ...
+"""
+import logging
+import os.path
+import re
+import subprocess
+import sys
+
+
+# The compiled whitelist RE.
+whitelist_re = None
+
+
+def LoadWhitelist(filename):
+  """ Load and compile whitelist regular expressions from filename.
+  """
+  lines = []
+  with open(filename, 'r') as f:
+    for line in f:
+      line = line.strip()
+      if not line or line.startswith('#'):
+        continue
+      lines.append(line)
+  combined_re = r'^(%s)$' % '|'.join(lines)
+  global whitelist_re
+  try:
+    whitelist_re = re.compile(combined_re)
+  except re.error:
+    logging.exception(
+        'Cannot compile package whitelist regular expression: %r',
+        combined_re)
+    whitelist_re = None
+    return False
+  return True
+
+
+def CheckJar(jar):
+  """Check a jar file.
+  """
+  # Get the list of files inside the jar file.
+  p = subprocess.Popen(args='jar tf %s' % jar,
+      stdout=subprocess.PIPE, shell=True)
+  stdout, _ = p.communicate()
+  if p.returncode != 0:
+    return False
+  items = stdout.split()
+  for f in items:
+    if f.endswith('.class'):
+      package_name = os.path.dirname(f)
+      package_name = package_name.replace('/', '.')
+      # Skip class without a package name
+      if package_name and not whitelist_re.match(package_name):
+        print >> sys.stderr, ('Error: %s: unknown package name of class file %s'
+                              % (jar, f))
+        return False
+  return True
+
+
+def main(argv):
+  if len(argv) < 2:
+    print __doc__
+    sys.exit(1)
+
+  if not LoadWhitelist(argv[0]):
+    sys.exit(1)
+
+  passed = True
+  for jar in argv[1:]:
+    if not CheckJar(jar):
+      passed = False
+  if not passed:
+    return 1
+
+  return 0
+
+
+if __name__ == '__main__':
+  main(sys.argv[1:])
diff --git a/core/tasks/check_boot_jars/package_whitelist.txt b/core/tasks/check_boot_jars/package_whitelist.txt
new file mode 100644
index 0000000..4d62615
--- /dev/null
+++ b/core/tasks/check_boot_jars/package_whitelist.txt
@@ -0,0 +1,214 @@
+# Boot jar package name whitelist.
+# Each line is interpreted as a regular expression.
+
+###################################################
+# core-libart.jar
+java\.awt\.font
+java\.beans
+java\.io
+java\.lang
+java\.lang\.annotation
+java\.lang\.ref
+java\.lang\.reflect
+java\.math
+java\.net
+java\.nio
+java\.nio\.channels
+java\.nio\.channels\.spi
+java\.nio\.charset
+java\.nio\.charset\.spi
+java\.security
+java\.security\.acl
+java\.security\.cert
+java\.security\.interfaces
+java\.security\.spec
+java\.sql
+java\.text
+java\.util
+java\.util\.concurrent
+java\.util\.concurrent\.atomic
+java\.util\.concurrent\.locks
+java\.util\.jar
+java\.util\.logging
+java\.util\.prefs
+java\.util\.regex
+java\.util\.zip
+javax\.crypto
+javax\.crypto\.interfaces
+javax\.crypto\.spec
+javax\.net
+javax\.net\.ssl
+javax\.security\.auth
+javax\.security\.auth\.callback
+javax\.security\.auth\.login
+javax\.security\.auth\.x500
+javax\.security\.cert
+javax\.sql
+javax\.xml
+javax\.xml\.datatype
+javax\.xml\.namespace
+javax\.xml\.parsers
+javax\.xml\.transform
+javax\.xml\.transform\.dom
+javax\.xml\.transform\.sax
+javax\.xml\.transform\.stream
+javax\.xml\.validation
+javax\.xml\.xpath
+sun\.misc
+org\.w3c\.dom
+org\.w3c\.dom\.ls
+org\.w3c\.dom\.traversal
+
+# TODO: Move these internal org.apache.harmony classes to libcore.*
+org\.apache\.harmony\.crypto\.internal
+org\.apache\.harmony\.dalvik
+org\.apache\.harmony\.dalvik\.ddmc
+org\.apache\.harmony\.luni\.internal\.util
+org\.apache\.harmony\.security
+org\.apache\.harmony\.security\.asn1
+org\.apache\.harmony\.security\.fortress
+org\.apache\.harmony\.security\.pkcs10
+org\.apache\.harmony\.security\.pkcs7
+org\.apache\.harmony\.security\.pkcs8
+org\.apache\.harmony\.security\.provider\.crypto
+org\.apache\.harmony\.security\.utils
+org\.apache\.harmony\.security\.x501
+org\.apache\.harmony\.security\.x509
+org\.apache\.harmony\.security\.x509\.tsp
+org\.apache\.harmony\.xml
+org\.apache\.harmony\.xml\.dom
+org\.apache\.harmony\.xml\.parsers
+
+org\.json
+org\.xmlpull\.v1
+org\.xmlpull\.v1\.sax2
+
+# TODO:  jarjar org.kxml2.io to com.android org\.kxml2\.io
+org\.kxml2\.io
+org\.xml
+org\.xml\.sax
+org\.xml\.sax\.ext
+org\.xml\.sax\.helpers
+
+dalvik\..*
+libcore\..*
+android\..*
+com\.android\..*
+
+
+###################################################
+# core-junit.jar
+junit\.extensions
+junit\.framework
+
+
+###################################################
+# ext.jar
+# TODO: jarjar javax.sip to com.android
+javax\.sip
+javax\.sip\.address
+javax\.sip\.header
+javax\.sip\.message
+
+# TODO: jarjar org.apache.commons to com.android
+org\.apache\.commons\.codec
+org\.apache\.commons\.codec\.binary
+org\.apache\.commons\.codec\.language
+org\.apache\.commons\.codec\.net
+org\.apache\.commons\.logging
+org\.apache\.commons\.logging\.impl
+org\.apache\.http
+org\.apache\.http\.auth
+org\.apache\.http\.auth\.params
+org\.apache\.http\.client
+org\.apache\.http\.client\.entity
+org\.apache\.http\.client\.methods
+org\.apache\.http\.client\.params
+org\.apache\.http\.client\.protocol
+org\.apache\.http\.client\.utils
+org\.apache\.http\.conn
+org\.apache\.http\.conn\.params
+org\.apache\.http\.conn\.routing
+org\.apache\.http\.conn\.scheme
+org\.apache\.http\.conn\.ssl
+org\.apache\.http\.conn\.util
+org\.apache\.http\.cookie
+org\.apache\.http\.cookie\.params
+org\.apache\.http\.entity
+org\.apache\.http\.impl
+org\.apache\.http\.impl\.auth
+org\.apache\.http\.impl\.client
+org\.apache\.http\.impl\.client
+org\.apache\.http\.impl\.conn
+org\.apache\.http\.impl\.conn\.tsccm
+org\.apache\.http\.impl\.cookie
+org\.apache\.http\.impl\.entity
+org\.apache\.http\.impl\.io
+org\.apache\.http\.impl\.io
+org\.apache\.http\.io
+org\.apache\.http\.message
+org\.apache\.http\.params
+org\.apache\.http\.protocol
+org\.apache\.http\.util
+
+# TODO: jarjar gov.nist to com.android
+gov\.nist\.core
+gov\.nist\.core\.net
+gov\.nist\.javax\.sip
+gov\.nist\.javax\.sip\.address
+gov\.nist\.javax\.sip\.clientauthutils
+gov\.nist\.javax\.sip\.header
+gov\.nist\.javax\.sip\.header\.extensions
+gov\.nist\.javax\.sip\.header\.ims
+gov\.nist\.javax\.sip\.message
+gov\.nist\.javax\.sip\.parser
+gov\.nist\.javax\.sip\.parser\.extensions
+gov\.nist\.javax\.sip\.parser\.ims
+gov\.nist\.javax\.sip\.stack
+
+org\.ccil\.cowan\.tagsoup
+org\.ccil\.cowan\.tagsoup\.jaxp
+
+###################################################
+# framework.jar
+javax\.microedition\.khronos\.opengles
+javax\.microedition\.khronos\.egl
+
+android
+
+
+###################################################
+# telephony-common.jar
+com\.google\..*
+
+
+###################################################
+# apache-xml.jar
+org\.apache\.xml\.res
+org\.apache\.xml\.utils
+org\.apache\.xml\.utils\.res
+org\.apache\.xml\.dtm
+org\.apache\.xml\.dtm\.ref
+org\.apache\.xml\.dtm\.ref\.dom2dtm
+org\.apache\.xml\.dtm\.ref\.sax2dtm
+org\.apache\.xml\.serializer
+org\.apache\.xml\.serializer\.utils
+org\.apache\.xml\.serializer\.dom3
+org\.apache\.xpath
+org\.apache\.xpath\.operations
+org\.apache\.xpath\.domapi
+org\.apache\.xpath\.functions
+org\.apache\.xpath\.res
+org\.apache\.xpath\.axes
+org\.apache\.xpath\.objects
+org\.apache\.xpath\.patterns
+org\.apache\.xpath\.jaxp
+org\.apache\.xpath\.compiler
+org\.apache\.xalan
+org\.apache\.xalan\.res
+org\.apache\.xalan\.templates
+org\.apache\.xalan\.serialize
+org\.apache\.xalan\.extensions
+org\.apache\.xalan\.processor
+org\.apache\.xalan\.transformer
+org\.apache\.xalan\.xslt
diff --git a/core/tasks/cts.mk b/core/tasks/cts.mk
index c521fa3..156f3df 100644
--- a/core/tasks/cts.mk
+++ b/core/tasks/cts.mk
@@ -17,8 +17,7 @@
 
 cts_name := android-cts
 
-DDMLIB_JAR := $(HOST_OUT_JAVA_LIBRARIES)/ddmlib-prebuilt.jar
-junit_host_jar := $(HOST_OUT_JAVA_LIBRARIES)/junit.jar
+JUNIT_HOST_JAR := $(HOST_OUT_JAVA_LIBRARIES)/junit.jar
 HOSTTESTLIB_JAR := $(HOST_OUT_JAVA_LIBRARIES)/hosttestlib.jar
 TF_JAR := $(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar
 CTS_TF_JAR := $(HOST_OUT_JAVA_LIBRARIES)/cts-tradefed.jar
@@ -48,6 +47,7 @@
 	android.core.tests.libcore.package.harmony_java_text \
 	android.core.tests.libcore.package.harmony_java_util \
 	android.core.tests.libcore.package.harmony_javax_security \
+	android.core.tests.libcore.package.okhttp \
 	android.core.tests.runner
 
 # The list of test packages that apache-harmony-tests (external/apache-harmony/Android.mk)
@@ -58,19 +58,33 @@
 	android.core.tests.libcore.package.harmony_prefs \
 	android.core.tests.libcore.package.harmony_sql
 
+
+CTS_TEST_JAR_LIST := \
+        cts-junit \
+	CtsJdwp
+
 # Depend on the full package paths rather than the phony targets to avoid
 # rebuilding the packages every time.
 CTS_CORE_CASES := $(foreach pkg,$(CTS_CORE_CASE_LIST),$(call intermediates-dir-for,APPS,$(pkg))/package.apk)
+CTS_TEST_JAR_FILES := $(foreach c,$(CTS_TEST_JAR_LIST),$(call intermediates-dir-for,JAVA_LIBRARIES,$(c))/javalib.jar)
 
 -include cts/CtsTestCaseList.mk
 CTS_CASE_LIST := $(CTS_CORE_CASE_LIST) $(CTS_TEST_CASE_LIST)
 
+# A module may have mutliple installed files (e.g. split apks)
+CTS_CASE_LIST_APKS :=
+CTS_CASE_LIST_APKS_DIR := $(cts_dir)/$(cts_name)/repository/testcases/
+$(foreach m, $(CTS_CASE_LIST),\
+  $(foreach fp, $(ALL_MODULES.$(m).BUILT_INSTALLED),\
+    $(eval pair := $(subst :,$(space),$(fp)))\
+    $(eval built := $(word 1,$(pair)))\
+    $(eval installed := $(CTS_CASE_LIST_APKS_DIR)/$(notdir $(word 2,$(pair))))\
+    $(eval $(call copy-one-file, $(built), $(installed)))\
+    $(eval CTS_CASE_LIST_APKS += $(installed))))
+
 DEFAULT_TEST_PLAN := $(cts_dir)/$(cts_name)/resource/plans
-CTS_TEST_CASE_LIST_FILES := $(foreach c, $(CTS_TEST_CASE_LIST), $(call intermediates-dir-for,APPS,$(c))/package.apk)
-$(cts_dir)/all_cts_files_stamp: PRIVATE_JUNIT_HOST_JAR := $(junit_host_jar)
-$(cts_dir)/all_cts_files_stamp: $(CTS_CORE_CASES) $(CTS_TEST_CASES) $(CTS_TEST_CASE_LIST_FILES) $(junit_host_jar) $(HOSTTESTLIB_JAR) $(CTS_HOST_LIBRARY_JARS) $(TF_JAR) $(VMTESTSTF_JAR) $(CTS_TF_JAR) $(CTS_TF_EXEC_PATH) $(CTS_TF_README_PATH) $(ACP)
+$(cts_dir)/all_cts_files_stamp: $(CTS_CORE_CASES) $(CTS_TEST_CASES) $(CTS_CASE_LIST_APKS) $(JUNIT_HOST_JAR) $(HOSTTESTLIB_JAR) $(CTS_HOST_LIBRARY_JARS) $(TF_JAR) $(VMTESTSTF_JAR) $(CTS_TF_JAR) $(CTS_TF_EXEC_PATH) $(CTS_TF_README_PATH) $(ACP) $(CTS_TEST_JAR_FILES)
 # Make necessary directory for CTS
-	$(hide) rm -rf $(PRIVATE_CTS_DIR)
 	$(hide) mkdir -p $(TMP_DIR)
 	$(hide) mkdir -p $(PRIVATE_DIR)/docs
 	$(hide) mkdir -p $(PRIVATE_DIR)/tools
@@ -78,9 +92,9 @@
 	$(hide) mkdir -p $(PRIVATE_DIR)/repository/plans
 # Copy executable and JARs to CTS directory
 	$(hide) $(ACP) -fp $(VMTESTSTF_JAR) $(PRIVATE_DIR)/repository/testcases
-	$(hide) $(ACP) -fp $(DDMLIB_JAR) $(PRIVATE_JUNIT_HOST_JAR) $(HOSTTESTLIB_JAR) $(CTS_HOST_LIBRARY_JARS) $(TF_JAR) $(CTS_TF_JAR) $(CTS_TF_EXEC_PATH) $(CTS_TF_README_PATH) $(PRIVATE_DIR)/tools
+	$(hide) $(ACP) -fp $(HOSTTESTLIB_JAR) $(CTS_HOST_LIBRARY_JARS) $(TF_JAR) $(CTS_TF_JAR) $(CTS_TF_EXEC_PATH) $(CTS_TF_README_PATH) $(PRIVATE_DIR)/tools
 # Change mode of the executables
-	$(foreach apk,$(CTS_CASE_LIST),$(call copy-testcase-apk,$(apk)))
+	$(foreach jar,$(CTS_TEST_JAR_LIST),$(call copy-testcase-jar,$(jar)))
 	$(foreach testcase,$(CTS_TEST_CASES),$(call copy-testcase,$(testcase)))
 	$(hide) touch $@
 
@@ -95,8 +109,8 @@
 define generate-core-test-description
 @echo "Generate core-test description ("$(notdir $(1))")"
 $(hide) java -Xmx256M \
-	-Xbootclasspath/a:$(PRIVATE_CLASSPATH) \
-	-classpath $(PRIVATE_CLASSPATH):$(HOST_OUT_JAVA_LIBRARIES)/descGen.jar:$(HOST_OUT_JAVA_LIBRARIES)/junit.jar:$(HOST_JDK_TOOLS_JAR) \
+	-Xbootclasspath/a:$(PRIVATE_CLASSPATH):$(JUNIT_HOST_JAR) \
+	-classpath $(HOST_OUT_JAVA_LIBRARIES)/descGen.jar:$(HOST_JDK_TOOLS_JAR) \
 	$(PRIVATE_PARAMS) CollectAllTests $(1) $(2) $(3) "$(4)" $(5) $(6)
 endef
 
@@ -104,15 +118,17 @@
 CONSCRYPT_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,conscrypt,,COMMON)
 BOUNCYCASTLE_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,bouncycastle,,COMMON)
 APACHEXML_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,apache-xml,,COMMON)
-OKHTTP_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,okhttp,,COMMON)
-APACHEHARMONY_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,apache-harmony-tests,,COMMON)
+OKHTTP_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,okhttp-nojarjar,,COMMON)
+OKHTTPTESTS_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,okhttp-tests-nojarjar,,COMMON)
+OKHTTP_REPACKAGED_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,okhttp,,COMMON)
+APACHEHARMONYTESTS_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,apache-harmony-tests,,COMMON)
 SQLITEJDBC_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,sqlite-jdbc,,COMMON)
 JUNIT_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,core-junit,,COMMON)
 CORETESTS_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,core-tests,,COMMON)
 JSR166TESTS_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,jsr166-tests,,COMMON)
 CONSCRYPTTESTS_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,conscrypt-tests,,COMMON)
 
-GEN_CLASSPATH := $(CORE_INTERMEDIATES)/classes.jar:$(CONSCRYPT_INTERMEDIATES)/classes.jar:$(BOUNCYCASTLE_INTERMEDIATES)/classes.jar:$(APACHEXML_INTERMEDIATES)/classes.jar:$(APACHEHARMONY_INTERMEDIATES)/classes.jar:$(OKHTTP_INTERMEDIATES)/classes.jar:$(JUNIT_INTERMEDIATES)/classes.jar:$(SQLITEJDBC_INTERMEDIATES)/javalib.jar:$(CORETESTS_INTERMEDIATES)/javalib.jar:$(JSR166TESTS_INTERMEDIATES)/javalib.jar:$(CONSCRYPTTESTS_INTERMEDIATES)/javalib.jar
+GEN_CLASSPATH := $(CORE_INTERMEDIATES)/classes.jar:$(CONSCRYPT_INTERMEDIATES)/classes.jar:$(BOUNCYCASTLE_INTERMEDIATES)/classes.jar:$(APACHEXML_INTERMEDIATES)/classes.jar:$(APACHEHARMONYTESTS_INTERMEDIATES)/classes.jar:$(OKHTTP_INTERMEDIATES)/classes.jar:$(OKHTTPTESTS_INTERMEDIATES)/classes.jar:$(OKHTTP_REPACKAGED_INTERMEDIATES)/classes.jar:$(JUNIT_INTERMEDIATES)/classes.jar:$(SQLITEJDBC_INTERMEDIATES)/javalib.jar:$(CORETESTS_INTERMEDIATES)/javalib.jar:$(JSR166TESTS_INTERMEDIATES)/javalib.jar:$(CONSCRYPTTESTS_INTERMEDIATES)/javalib.jar
 
 CTS_CORE_XMLS := \
 	$(CTS_TESTCASES_OUT)/android.core.tests.libcore.package.dalvik.xml \
@@ -136,6 +152,7 @@
 	$(CTS_TESTCASES_OUT)/android.core.tests.libcore.package.harmony_logging.xml \
 	$(CTS_TESTCASES_OUT)/android.core.tests.libcore.package.harmony_prefs.xml \
 	$(CTS_TESTCASES_OUT)/android.core.tests.libcore.package.harmony_sql.xml \
+	$(CTS_TESTCASES_OUT)/android.core.tests.libcore.package.okhttp.xml \
 
 $(CTS_CORE_XMLS): PRIVATE_CLASSPATH:=$(GEN_CLASSPATH)
 # Why does this depend on javalib.jar instead of classes.jar?  Because
@@ -143,7 +160,7 @@
 # build system requires that dependencies use javalib.jar.  If
 # javalib.jar is up-to-date, then classes.jar is as well.  Depending
 # on classes.jar will build the files incorrectly.
-CTS_CORE_XMLS_DEPS := $(CTS_CORE_CASES) $(HOST_OUT_JAVA_LIBRARIES)/descGen.jar $(HOST_OUT_JAVA_LIBRARIES)/junit.jar $(CORE_INTERMEDIATES)/javalib.jar $(BOUNCYCASTLE_INTERMEDIATES)/javalib.jar $(APACHEXML_INTERMEDIATES)/javalib.jar $(APACHEHARMONY_INTERMEDIATES)/javalib.jar $(OKHTTP_INTERMEDIATES)/javalib.jar $(SQLITEJDBC_INTERMEDIATES)/javalib.jar $(JUNIT_INTERMEDIATES)/javalib.jar $(CORETESTS_INTERMEDIATES)/javalib.jar $(JSR166TESTS_INTERMEDIATES)/javalib.jar $(CONSCRYPTTESTS_INTERMEDIATES)/javalib.jar build/core/tasks/cts.mk | $(ACP)
+CTS_CORE_XMLS_DEPS := $(CTS_CORE_CASES) $(HOST_OUT_JAVA_LIBRARIES)/descGen.jar $(JUNIT_HOST_JAR) $(CORE_INTERMEDIATES)/javalib.jar $(BOUNCYCASTLE_INTERMEDIATES)/javalib.jar $(APACHEXML_INTERMEDIATES)/javalib.jar $(APACHEHARMONYTESTS_INTERMEDIATES)/javalib.jar $(OKHTTP_INTERMEDIATES)/javalib.jar $(OKHTTPTESTS_INTERMEDIATES)/javalib.jar $(OKHTTP_REPACKAGED_INTERMEDIATES)/javalib.jar $(SQLITEJDBC_INTERMEDIATES)/javalib.jar $(JUNIT_INTERMEDIATES)/javalib.jar $(CORETESTS_INTERMEDIATES)/javalib.jar $(JSR166TESTS_INTERMEDIATES)/javalib.jar $(CONSCRYPTTESTS_INTERMEDIATES)/javalib.jar build/core/tasks/cts.mk | $(ACP)
 
 $(CTS_TESTCASES_OUT)/android.core.tests.libcore.package.dalvik.xml: $(CTS_CORE_XMLS_DEPS)
 	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
@@ -268,31 +285,37 @@
 	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
 	$(call generate-core-test-description,$(CTS_TESTCASES_OUT)/android.core.tests.libcore.package.harmony_beans,\
 		cts/tests/core/libcore/harmony_beans/AndroidManifest.xml,\
-		$(APACHEHARMONY_INTERMEDIATES)/javalib.jar,com.android.org.apache.harmony.beans,\
+		$(APACHEHARMONYTESTS_INTERMEDIATES)/javalib.jar,com.android.org.apache.harmony.beans,\
 		libcore/expectations external/apache-harmony/Android.mk)
 
 $(CTS_TESTCASES_OUT)/android.core.tests.libcore.package.harmony_logging.xml: $(CTS_CORE_XMLS_DEPS)
 	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
 	$(call generate-core-test-description,$(CTS_TESTCASES_OUT)/android.core.tests.libcore.package.harmony_logging,\
 		cts/tests/core/libcore/harmony_logging/AndroidManifest.xml,\
-		$(APACHEHARMONY_INTERMEDIATES)/javalib.jar,com.android.org.apache.harmony.logging,\
+		$(APACHEHARMONYTESTS_INTERMEDIATES)/javalib.jar,com.android.org.apache.harmony.logging,\
 		libcore/expectations external/apache-harmony/Android.mk)
 
-
 $(CTS_TESTCASES_OUT)/android.core.tests.libcore.package.harmony_prefs.xml: $(CTS_CORE_XMLS_DEPS)
 	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
 	$(call generate-core-test-description,$(CTS_TESTCASES_OUT)/android.core.tests.libcore.package.harmony_prefs,\
 		cts/tests/core/libcore/harmony_prefs/AndroidManifest.xml,\
-		$(APACHEHARMONY_INTERMEDIATES)/javalib.jar,com.android.org.apache.harmony.prefs,\
+		$(APACHEHARMONYTESTS_INTERMEDIATES)/javalib.jar,com.android.org.apache.harmony.prefs,\
 		libcore/expectations external/apache-harmony/Android.mk)
 
 $(CTS_TESTCASES_OUT)/android.core.tests.libcore.package.harmony_sql.xml: $(CTS_CORE_XMLS_DEPS)
 	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
 	$(call generate-core-test-description,$(CTS_TESTCASES_OUT)/android.core.tests.libcore.package.harmony_sql,\
 		cts/tests/core/libcore/harmony_sql/AndroidManifest.xml,\
-		$(APACHEHARMONY_INTERMEDIATES)/javalib.jar,com.android.org.apache.harmony.sql,\
+		$(APACHEHARMONYTESTS_INTERMEDIATES)/javalib.jar,com.android.org.apache.harmony.sql,\
 		libcore/expectations external/apache-harmony/Android.mk)
 
+$(CTS_TESTCASES_OUT)/android.core.tests.libcore.package.okhttp.xml: $(CTS_CORE_XMLS_DEPS)
+	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
+	$(call generate-core-test-description,$(CTS_TESTCASES_OUT)/android.core.tests.libcore.package.okhttp,\
+		cts/tests/core/libcore/okhttp/AndroidManifest.xml,\
+		$(OKHTTPTESTS_INTERMEDIATES)/javalib.jar,,\
+		libcore/expectations)
+
 # ----- Generate the test descriptions for the vm-tests-tf -----
 #
 CORE_VM_TEST_TF_DESC := $(CTS_TESTCASES_OUT)/android.core.vm-tests-tf.xml
@@ -301,11 +324,11 @@
 CORE_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,core-libart,,COMMON)
 JUNIT_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,core-junit,,COMMON)
 
-GEN_CLASSPATH := $(CORE_INTERMEDIATES)/classes.jar:$(JUNIT_INTERMEDIATES)/classes.jar:$(VMTESTSTF_JAR):$(DDMLIB_JAR):$(TF_JAR)
+GEN_CLASSPATH := $(CORE_INTERMEDIATES)/classes.jar:$(JUNIT_INTERMEDIATES)/classes.jar:$(VMTESTSTF_JAR):$(TF_JAR)
 
 $(CORE_VM_TEST_TF_DESC): PRIVATE_CLASSPATH:=$(GEN_CLASSPATH)
 # Please see big comment above on why this line depends on javalib.jar instead of classes.jar
-$(CORE_VM_TEST_TF_DESC): $(HOST_OUT_JAVA_LIBRARIES)/descGen.jar $(HOST_OUT_JAVA_LIBRARIES)/junit.jar $(CORE_INTERMEDIATES)/javalib.jar $(JUNIT_INTERMEDIATES)/javalib.jar $(VMTESTSTF_JAR) $(DDMLIB_JAR) | $(ACP)
+$(CORE_VM_TEST_TF_DESC): $(HOST_OUT_JAVA_LIBRARIES)/descGen.jar $(JUNIT_HOST_JAR) $(CORE_INTERMEDIATES)/javalib.jar $(JUNIT_INTERMEDIATES)/javalib.jar $(VMTESTSTF_JAR) | $(ACP)
 	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
 	$(call generate-core-test-description,$(CTS_TESTCASES_OUT)/android.core.vm-tests-tf,\
 		cts/tests/vm-tests-tf/AndroidManifest.xml,\
@@ -339,15 +362,16 @@
 cts: $(INTERNAL_CTS_TARGET) adb
 $(call dist-for-goals,cts,$(INTERNAL_CTS_TARGET))
 
-define copy-testcase-apk
-
-$(hide) $(ACP) -fp $(call intermediates-dir-for,APPS,$(1))/package.apk \
-	$(PRIVATE_DIR)/repository/testcases/$(1).apk
-
-endef
 
 define copy-testcase
 
 $(hide) $(ACP) -fp $(1) $(PRIVATE_DIR)/repository/testcases/$(notdir $1)
 
 endef
+
+define copy-testcase-jar
+
+$(hide) $(ACP) -fp $(call intermediates-dir-for,JAVA_LIBRARIES,$(1))/javalib.jar \
+	$(PRIVATE_DIR)/repository/testcases/$(1).jar
+
+endef
diff --git a/core/tasks/oem_image.mk b/core/tasks/oem_image.mk
new file mode 100644
index 0000000..26b9aba
--- /dev/null
+++ b/core/tasks/oem_image.mk
@@ -0,0 +1,46 @@
+#
+# 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.
+#
+
+# We build oem.img only if it's asked for.
+ifneq ($(filter $(MAKECMDGOALS),oem_image),)
+ifndef BOARD_OEMIMAGE_PARTITION_SIZE
+$(error BOARD_OEMIMAGE_PARTITION_SIZE is not set.)
+endif
+
+INTERNAL_OEMIMAGE_FILES := \
+    $(filter $(TARGET_OUT_OEM)/%,$(ALL_DEFAULT_INSTALLED_MODULES))
+
+oemimage_intermediates := \
+    $(call intermediates-dir-for,PACKAGING,oem)
+BUILT_OEMIMAGE_TARGET := $(PRODUCT_OUT)/oem.img
+# We just build this directly to the install location.
+INSTALLED_OEMIMAGE_TARGET := $(BUILT_OEMIMAGE_TARGET)
+
+$(INSTALLED_OEMIMAGE_TARGET) : $(INTERNAL_USERIMAGES_DEPS) $(INTERNAL_OEMIMAGE_FILES)
+	$(call pretty,"Target oem fs image: $@")
+	@mkdir -p $(TARGET_OUT_OEM)
+	@mkdir -p $(oemimage_intermediates) && rm -rf $(oemimage_intermediates)/oem_image_info.txt
+	$(call generate-userimage-prop-dictionary, $(oemimage_intermediates)/oem_image_info.txt, skip_fsck=true)
+	$(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH \
+	  ./build/tools/releasetools/build_image.py \
+	  $(TARGET_OUT_OEM) $(oemimage_intermediates)/oem_image_info.txt $@
+	$(hide) $(call assert-max-image-size,$@,$(BOARD_OEMIMAGE_PARTITION_SIZE))
+
+.PHONY: oem_image
+oem_image : $(INSTALLED_OEMIMAGE_TARGET)
+$(call dist-for-goals, oem_image, $(INSTALLED_OEMIMAGE_TARGET))
+
+endif  # oem_image in $(MAKECMDGOALS)
diff --git a/core/tasks/sdk-addon.mk b/core/tasks/sdk-addon.mk
index 5a24a00..b32536c 100644
--- a/core/tasks/sdk-addon.mk
+++ b/core/tasks/sdk-addon.mk
@@ -18,11 +18,12 @@
 addon_name := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SDK_ADDON_NAME))
 ifneq ($(addon_name),)
 
-addon_dir_leaf := $(addon_name)-$(FILE_NAME_TAG)-$(INTERNAL_SDK_HOST_OS_NAME)
-
-intermediates := $(HOST_OUT_INTERMEDIATES)/SDK_ADDON/$(addon_name)_intermediates
-full_target := $(HOST_OUT_SDK_ADDON)/$(addon_dir_leaf).zip
-staging := $(intermediates)/$(addon_dir_leaf)
+addon_dir_leaf  := $(addon_name)-$(FILE_NAME_TAG)-$(INTERNAL_SDK_HOST_OS_NAME)
+addon_dir_img   := $(addon_dir_leaf)-img
+intermediates   := $(HOST_OUT_INTERMEDIATES)/SDK_ADDON/$(addon_name)_intermediates
+full_target     := $(HOST_OUT_SDK_ADDON)/$(addon_dir_leaf).zip
+full_target_img := $(HOST_OUT_SDK_ADDON)/$(addon_dir_img).zip
+staging         := $(intermediates)
 
 sdk_addon_deps :=
 files_to_copy :=
@@ -46,29 +47,54 @@
   $(eval _src := $(call stub-addon-jar-file,$(_src))) \
   $(if $(_src),,$(eval $(error Unknown or unlinkable module: $(call word-colon,1,$(cf)). Requested by $(INTERNAL_PRODUCT)))) \
   $(eval _dest := $(call word-colon,2,$(cf))) \
-  $(eval files_to_copy += $(_src):$(_dest)) \
+  $(eval files_to_copy += $(addon_dir_leaf):$(_src):$(_dest)) \
  )
 endif
 
 # Files that are copied directly into the sdk-addon
-files_to_copy += $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SDK_ADDON_COPY_FILES)
+ifneq ($(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SDK_ADDON_COPY_FILES)),)
+$(foreach cf,$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SDK_ADDON_COPY_FILES), \
+  $(eval _src  := $(call word-colon,1,$(cf))) \
+  $(eval _dest := $(call word-colon,2,$(cf))) \
+  $(if $(findstring images/,$(_dest)), $(eval _root := $(addon_dir_img)), $(eval _root := $(addon_dir_leaf))) \
+  $(eval files_to_copy += $(_root):$(_src):$(_dest)) \
+ )
+endif
 
-# All SDK add-ons have these files
+# Files copied in the system-image directory
 files_to_copy += \
-        $(BUILT_SYSTEMIMAGE):images/$(TARGET_CPU_ABI)/system.img \
-        $(BUILT_USERDATAIMAGE_TARGET):images/$(TARGET_CPU_ABI)/userdata.img \
-        $(BUILT_RAMDISK_TARGET):images/$(TARGET_CPU_ABI)/ramdisk.img \
-        $(PRODUCT_OUT)/system/build.prop:images/$(TARGET_CPU_ABI)/build.prop \
-        $(target_notice_file_txt):images/$(TARGET_CPU_ABI)/NOTICE.txt
+	$(addon_dir_img):$(BUILT_SYSTEMIMAGE):images/$(TARGET_CPU_ABI)/system.img \
+	$(addon_dir_img):$(BUILT_USERDATAIMAGE_TARGET):images/$(TARGET_CPU_ABI)/userdata.img \
+	$(addon_dir_img):$(BUILT_RAMDISK_TARGET):images/$(TARGET_CPU_ABI)/ramdisk.img \
+	$(addon_dir_img):$(PRODUCT_OUT)/system/build.prop:images/$(TARGET_CPU_ABI)/build.prop \
+	$(addon_dir_img):$(target_notice_file_txt):images/$(TARGET_CPU_ABI)/NOTICE.txt \
+	$(addon_dir_img):$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SDK_ADDON_SYS_IMG_SOURCE_PROP):images/source.properties
 
 # Generate rules to copy the requested files
 $(foreach cf,$(files_to_copy), \
-  $(eval _src := $(call word-colon,1,$(cf))) \
-  $(eval _dest := $(call append-path,$(staging),$(call word-colon,2,$(cf)))) \
+  $(eval _root := $(call word-colon,1,$(cf))) \
+  $(eval _src  := $(call word-colon,2,$(cf))) \
+  $(eval _dest := $(call append-path,$(call append-path,$(staging),$(_root)),$(call word-colon,3,$(cf)))) \
   $(eval $(call copy-one-file,$(_src),$(_dest))) \
   $(eval sdk_addon_deps += $(_dest)) \
  )
 
+# The system-image source.properties is a template that we directly expand in-place
+addon_img_source_prop := $(call append-path,$(staging),$(addon_dir_img))/images/source.properties
+sdk_addon_deps += $(addon_img_source_prop)
+
+$(addon_img_source_prop): $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SDK_ADDON_SYS_IMG_SOURCE_PROP)
+	@echo Generate $@
+	$(hide) mkdir -p $(dir $@)
+	$(hide) sed \
+		-e 's/$${PLATFORM_VERSION}/$(PLATFORM_VERSION)/' \
+		-e 's/$${PLATFORM_SDK_VERSION}/$(PLATFORM_SDK_VERSION)/' \
+		-e 's/$${PLATFORM_VERSION_CODENAME}/$(subst REL,,$(PLATFORM_VERSION_CODENAME))/' \
+		-e 's/$${TARGET_ARCH}/$(TARGET_ARCH)/' \
+		-e 's/$${TARGET_CPU_ABI}/$(TARGET_CPU_ABI)/' \
+		$< > $@ && sed -i -e '/^AndroidVersion.CodeName=\s*$$/d' $@
+
+
 # We don't know about all of the docs files, so depend on the timestamps for
 # them, and record the directories, and the packaging rule will just copy the
 # whole thing.
@@ -76,7 +102,7 @@
 sdk_addon_deps += $(foreach dm, $(doc_modules), $(call doc-timestamp-for, $(dm)))
 $(full_target): PRIVATE_DOCS_DIRS := $(addprefix $(OUT_DOCS)/, $(doc_modules))
 
-$(full_target): PRIVATE_STAGING_DIR := $(staging)
+$(full_target): PRIVATE_STAGING_DIR := $(call append-path,$(staging),$(addon_dir_leaf))
 
 $(full_target): $(sdk_addon_deps) | $(ACP)
 	@echo Packaging SDK Addon: $@
@@ -85,16 +111,24 @@
 	    $(ACP) -r $$d $(PRIVATE_STAGING_DIR)/docs ;\
 	  done
 	$(hide) mkdir -p $(dir $@)
-	$(hide) ( F=$$(pwd)/$@ ; cd $(PRIVATE_STAGING_DIR)/.. && zip -rq $$F * )
+	$(hide) ( F=$$(pwd)/$@ ; cd $(PRIVATE_STAGING_DIR)/.. && zip -rq $$F $(notdir $(PRIVATE_STAGING_DIR)) )
+
+$(full_target_img): PRIVATE_STAGING_DIR := $(call append-path,$(staging),$(addon_dir_img))
+$(full_target_img): $(full_target) $(addon_img_source_prop)
+	@echo Packaging SDK Addon System-Image: $@
+	$(hide) mkdir -p $(dir $@)
+	$(hide) ( F=$$(pwd)/$@ ; cd $(PRIVATE_STAGING_DIR)/.. && zip -rq $$F $(notdir $(PRIVATE_STAGING_DIR)) )
+
 
 .PHONY: sdk_addon
-sdk_addon: $(full_target)
+sdk_addon: $(full_target) $(full_target_img)
 
 ifneq ($(sdk_repo_goal),)
 # If we're building the sdk_repo, keep the name of the addon zip
 # around so that development/build/tools/sdk_repo.mk can dist it
 # at the appropriate location.
-ADDON_SDK_ZIP := $(full_target)
+ADDON_SDK_ZIP        := $(full_target)
+ADDON_SDK_IMG_ZIP    := $(full_target_img)
 else
 # When not building an sdk_repo, just dist the addon zip file
 # as-is.
diff --git a/core/tasks/tools/package-modules.mk b/core/tasks/tools/package-modules.mk
index f7e04ed..bd9cf57 100644
--- a/core/tasks/tools/package-modules.mk
+++ b/core/tasks/tools/package-modules.mk
@@ -37,16 +37,26 @@
       $(eval my_copy_pairs += $(bui):$(my_staging_dir)/$(my_copy_dest)))\
   ))
 
+define copy-tests-in-batch
+$(hide) $(foreach p, $(1),\
+  $(eval pair := $(subst :,$(space),$(p)))\
+  mkdir -p $(dir $(word 2,$(pair)));\
+  cp -rf $(word 1,$(pair)) $(word 2,$(pair));)
+endef
+
 my_package_zip := $(my_staging_dir)/$(my_package_name).zip
 $(my_package_zip): PRIVATE_COPY_PAIRS := $(my_copy_pairs)
 $(my_package_zip): PRIVATE_PICKUP_FILES := $(my_pickup_files)
 $(my_package_zip) : $(my_built_modules)
 	@echo "Package $@"
 	@rm -rf $(dir $@) && mkdir -p $(dir $@)
-	$(hide) $(foreach p, $(PRIVATE_COPY_PAIRS), \
-	  $(eval pair := $(subst :,$(space),$(p)))\
-	  mkdir -p $(dir $(word 2,$(pair))); \
-	  cp -rf $(word 1,$(pair)) $(word 2,$(pair));)
-	$(hide) $(foreach f, $(PRIVATE_PICKUP_FILES), \
+	$(call copy-tests-in-batch,$(wordlist 1,200,$(PRIVATE_COPY_PAIRS)))
+	$(call copy-tests-in-batch,$(wordlist 201,400,$(PRIVATE_COPY_PAIRS)))
+	$(call copy-tests-in-batch,$(wordlist 401,600,$(PRIVATE_COPY_PAIRS)))
+	$(call copy-tests-in-batch,$(wordlist 601,800,$(PRIVATE_COPY_PAIRS)))
+	$(call copy-tests-in-batch,$(wordlist 801,1000,$(PRIVATE_COPY_PAIRS)))
+	$(call copy-tests-in-batch,$(wordlist 1001,1200,$(PRIVATE_COPY_PAIRS)))
+	$(call copy-tests-in-batch,$(wordlist 1201,9999,$(PRIVATE_COPY_PAIRS)))
+	$(hide) $(foreach f, $(PRIVATE_PICKUP_FILES),\
 	  cp -rf $(f) $(dir $@);)
 	$(hide) cd $(dir $@) && zip -rq $(notdir $@) *
diff --git a/core/tasks/vendor_module_check.mk b/core/tasks/vendor_module_check.mk
index 87d723c..d8e8ec7 100644
--- a/core/tasks/vendor_module_check.mk
+++ b/core/tasks/vendor_module_check.mk
@@ -18,19 +18,27 @@
 _vendor_owner_whitelist := \
         asus \
         audience \
+        atmel \
         broadcom \
         csr \
         elan \
         google \
+        htc \
         imgtec \
         invensense \
         intel \
         lge \
+        moto \
+        mtk \
         nvidia \
         nxp \
+        nxpsw \
         qcom \
+        qti \
         samsung \
         samsung_arm \
+        sony \
+        synaptics \
         ti \
         trusted_logic \
         widevine
diff --git a/core/version_defaults.mk b/core/version_defaults.mk
index 1e172ed..8cb8d26 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
+  PLATFORM_VERSION := 5.0
 endif
 
 ifeq "" "$(PLATFORM_SDK_VERSION)"
@@ -53,13 +53,18 @@
   # intermediate builds).  During development, this number remains at the
   # SDK version the branch is based on and PLATFORM_VERSION_CODENAME holds
   # the code-name of the new development work.
-  PLATFORM_SDK_VERSION := 19
+  PLATFORM_SDK_VERSION := 21
 endif
 
 ifeq "" "$(PLATFORM_VERSION_CODENAME)"
   # This is the current development code-name, if the build is not a final
   # release build.  If this is a final release build, it is simply "REL".
   PLATFORM_VERSION_CODENAME := REL
+
+  # This is all of the development codenames that are active.  Should be either
+  # the same as PLATFORM_VERSION_CODENAME or a comma-separated list of additional
+  # codenames after PLATFORM_VERSION_CODENAME.
+  PLATFORM_VERSION_ALL_CODENAMES := $(PLATFORM_VERSION_CODENAME)
 endif
 
 ifeq "" "$(DEFAULT_APP_TARGET_SDK)"
diff --git a/envsetup.sh b/envsetup.sh
index c29b788..a9bd707 100644
--- a/envsetup.sh
+++ b/envsetup.sh
@@ -1,9 +1,8 @@
-MAKE_UTIL=(`which make`)
 function hmm() {
 cat <<EOF
 Invoke ". build/envsetup.sh" from your shell to add the following functions to your environment:
 - lunch:   lunch <product_name>-<build_variant>
-- tapas:   tapas [<App1> <App2> ...] [arm|x86|mips|armv5] [eng|userdebug|user]
+- tapas:   tapas [<App1> <App2> ...] [arm|x86|mips|armv5|arm64|x86_64|mips64] [eng|userdebug|user]
 - croot:   Changes directory to the top of the tree.
 - m:       Makes from the top of the tree.
 - mm:      Builds all of the modules in the current directory, but not their dependencies.
@@ -12,8 +11,10 @@
 - mma:     Builds all of the modules in the current directory, and their dependencies.
 - mmma:    Builds all of the modules in the supplied directories, and their dependencies.
 - cgrep:   Greps on all local C/C++ files.
+- ggrep:   Greps on all local Gradle files.
 - jgrep:   Greps on all local Java files.
 - resgrep: Greps on all local res/*.xml files.
+- sgrep:   Greps on all local source files.
 - godir:   Go to the directory containing a file.
 
 Look at the source to view more functions. The complete list is:
@@ -21,7 +22,7 @@
     T=$(gettop)
     local A
     A=""
-    for i in `cat $T/build/envsetup.sh | sed -n "/^function /s/function \([a-z_]*\).*/\1/p" | sort`; do
+    for i in `cat $T/build/envsetup.sh | sed -n "/^[ \t]*function /s/function \([a-z_]*\).*/\1/p" | sort | uniq`; do
       A="$A $i"
     done
     echo $A
@@ -36,7 +37,7 @@
         return
     fi
     (\cd $T; CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \
-      $MAKE_UTIL --no-print-directory -f build/core/config.mk dumpvar-abs-$1)
+      command make --no-print-directory -f build/core/config.mk dumpvar-abs-$1)
 }
 
 # Get the exact value of a build variable.
@@ -48,7 +49,7 @@
         return
     fi
     (\cd $T; CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \
-      $MAKE_UTIL --no-print-directory -f build/core/config.mk dumpvar-$1)
+      command make --no-print-directory -f build/core/config.mk dumpvar-$1)
 }
 
 # check to see if the supplied product is one we can build
@@ -564,12 +565,12 @@
 complete -F _lunch lunch
 
 # Configures the build to build unbundled apps.
-# Run tapas with one ore more app names (from LOCAL_PACKAGE_NAME)
+# Run tapas with one or more app names (from LOCAL_PACKAGE_NAME)
 function tapas()
 {
-    local arch=$(echo -n $(echo $* | xargs -n 1 echo | \grep -E '^(arm|x86|mips|armv5)$'))
-    local variant=$(echo -n $(echo $* | xargs -n 1 echo | \grep -E '^(user|userdebug|eng)$'))
-    local apps=$(echo -n $(echo $* | xargs -n 1 echo | \grep -E -v '^(user|userdebug|eng|arm|x86|mips|armv5)$'))
+    local arch="$(echo $* | xargs -n 1 echo | \grep -E '^(arm|x86|mips|armv5|arm64|x86_64|mips64)$' | xargs)"
+    local variant="$(echo $* | xargs -n 1 echo | \grep -E '^(user|userdebug|eng)$' | xargs)"
+    local apps="$(echo $* | xargs -n 1 echo | \grep -E -v '^(user|userdebug|eng|arm|x86|mips|armv5|arm64|x86_64|mips64)$' | xargs)"
 
     if [ $(echo $arch | wc -w) -gt 1 ]; then
         echo "tapas: Error: Multiple build archs supplied: $arch"
@@ -582,9 +583,12 @@
 
     local product=full
     case $arch in
-      x86)   product=full_x86;;
-      mips)  product=full_mips;;
-      armv5) product=generic_armv5;;
+      x86)    product=full_x86;;
+      mips)   product=full_mips;;
+      armv5)  product=generic_armv5;;
+      arm64)  product=aosp_arm64;;
+      x86_64) product=aosp_x86_64;;
+      mips64)  product=aosp_mips64;;
     esac
     if [ -z "$variant" ]; then
         variant=eng
@@ -1036,11 +1040,16 @@
        fi
 
        OUT_SO_SYMBOLS=$OUT_SO_SYMBOLS$USE64BIT
+       OUT_VENDOR_SO_SYMBOLS=$OUT_VENDOR_SO_SYMBOLS$USE64BIT
 
        echo >|"$OUT_ROOT/gdbclient.cmds" "set solib-absolute-prefix $OUT_SYMBOLS"
        echo >>"$OUT_ROOT/gdbclient.cmds" "set solib-search-path $OUT_SO_SYMBOLS:$OUT_SO_SYMBOLS/hw:$OUT_SO_SYMBOLS/ssl/engines:$OUT_SO_SYMBOLS/drm:$OUT_SO_SYMBOLS/egl:$OUT_SO_SYMBOLS/soundfx:$OUT_VENDOR_SO_SYMBOLS:$OUT_VENDOR_SO_SYMBOLS/hw:$OUT_VENDOR_SO_SYMBOLS/egl"
        echo >>"$OUT_ROOT/gdbclient.cmds" "source $ANDROID_BUILD_TOP/development/scripts/gdb/dalvik.gdb"
        echo >>"$OUT_ROOT/gdbclient.cmds" "target remote $PORT"
+       # Enable special debugging for ART processes.
+       if [[ $EXE =~ (^|/)(app_process|dalvikvm)(|32|64)$ ]]; then
+          echo >> "$OUT_ROOT/gdbclient.cmds" "art-on"
+       fi
        echo >>"$OUT_ROOT/gdbclient.cmds" ""
 
        local WHICH_GDB=
@@ -1066,14 +1075,14 @@
     Darwin)
         function sgrep()
         {
-            find -E . -name .repo -prune -o -name .git -prune -o  -type f -iregex '.*\.(c|h|cpp|S|java|xml|sh|mk)' -print0 | xargs -0 grep --color -n "$@"
+            find -E . -name .repo -prune -o -name .git -prune -o  -type f -iregex '.*\.(c|h|cc|cpp|S|java|xml|sh|mk|aidl)' -print0 | xargs -0 grep --color -n "$@"
         }
 
         ;;
     *)
         function sgrep()
         {
-            find . -name .repo -prune -o -name .git -prune -o  -type f -iregex '.*\.\(c\|h\|cpp\|S\|java\|xml\|sh\|mk\)' -print0 | xargs -0 grep --color -n "$@"
+            find . -name .repo -prune -o -name .git -prune -o  -type f -iregex '.*\.\(c\|h\|cc\|cpp\|S\|java\|xml\|sh\|mk\|aidl\)' -print0 | xargs -0 grep --color -n "$@"
         }
         ;;
 esac
@@ -1083,6 +1092,11 @@
     get_build_var TARGET_ARCH
 }
 
+function ggrep()
+{
+    find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f -name "*\.gradle" -print0 | xargs -0 grep --color -n "$@"
+}
+
 function jgrep()
 {
     find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f -name "*\.java" -print0 | xargs -0 grep --color -n "$@"
@@ -1218,9 +1232,7 @@
     fi
 
     # issue "am" command to cause the hprof dump
-    local sdcard=$(adb ${adbOptions} shell echo -n '$EXTERNAL_STORAGE')
-    local devFile=$sdcard/hprof-$targetPid
-    #local devFile=/data/local/hprof-$targetPid
+    local devFile=/data/local/tmp/hprof-$targetPid
     echo "Poking $targetPid and waiting for data..."
     echo "Storing data at $devFile"
     adb ${adbOptions} shell am dumpheap $targetPid $devFile
@@ -1446,10 +1458,15 @@
     return $retval
 }
 
+function get_make_command()
+{
+  echo command make
+}
+
 function make()
 {
     local start_time=$(date +"%s")
-    $MAKE_UTIL "$@"
+    $(get_make_command) "$@"
     local ret=$?
     local end_time=$(date +"%s")
     local tdiff=$(($end_time-$start_time))
@@ -1458,9 +1475,9 @@
     local secs=$(($tdiff % 60))
     echo
     if [ $ret -eq 0 ] ; then
-        echo -n -e "\e[0;32m#### make completed successfully "
+        echo -n -e "#### make completed successfully "
     else
-        echo -n -e "\e[0;31m#### make failed to build some targets "
+        echo -n -e "#### make failed to build some targets "
     fi
     if [ $hours -gt 0 ] ; then
         printf "(%02g:%02g:%02g (hh:mm:ss))" $hours $mins $secs
@@ -1469,7 +1486,7 @@
     elif [ $secs -gt 0 ] ; then
         printf "(%s seconds)" $secs
     fi
-    echo -e " ####\e[00m"
+    echo -e " ####"
     echo
     return $ret
 }
diff --git a/target/board/generic/BoardConfig.mk b/target/board/generic/BoardConfig.mk
index d42b652..e06c985 100644
--- a/target/board/generic/BoardConfig.mk
+++ b/target/board/generic/BoardConfig.mk
@@ -92,3 +92,8 @@
         shell.te \
         surfaceflinger.te \
         system_server.te
+
+ifeq ($(TARGET_PRODUCT),sdk)
+  # include an expanded selection of fonts for the SDK.
+  EXTENDED_FONT_FOOTPRINT := true
+endif
diff --git a/target/board/generic/device.mk b/target/board/generic/device.mk
index fe64bcb..06a7d8a 100644
--- a/target/board/generic/device.mk
+++ b/target/board/generic/device.mk
@@ -25,6 +25,9 @@
 PRODUCT_COPY_FILES := \
     device/generic/goldfish/data/etc/apns-conf.xml:system/etc/apns-conf.xml \
     device/generic/goldfish/camera/media_profiles.xml:system/etc/media_profiles.xml \
+    frameworks/av/media/libstagefright/data/media_codecs_google_audio.xml:system/etc/media_codecs_google_audio.xml \
+    frameworks/av/media/libstagefright/data/media_codecs_google_telephony.xml:system/etc/media_codecs_google_telephony.xml \
+    frameworks/av/media/libstagefright/data/media_codecs_google_video.xml:system/etc/media_codecs_google_video.xml \
     device/generic/goldfish/camera/media_codecs.xml:system/etc/media_codecs.xml \
     hardware/libhardware_legacy/audio/audio_policy.conf:system/etc/audio_policy.conf
 
diff --git a/target/board/generic_arm64/BoardConfig.mk b/target/board/generic_arm64/BoardConfig.mk
index 1493bd9..c57447d 100644
--- a/target/board/generic_arm64/BoardConfig.mk
+++ b/target/board/generic_arm64/BoardConfig.mk
@@ -22,11 +22,39 @@
 TARGET_CPU_ABI := arm64-v8a
 
 TARGET_2ND_ARCH := arm
-TARGET_2ND_ARCH_VARIANT := armv7-a-neon
-TARGET_2ND_CPU_VARIANT := cortex-a15
 TARGET_2ND_CPU_ABI := armeabi-v7a
 TARGET_2ND_CPU_ABI2 := armeabi
 
+ifdef TARGET_BUILD_APPS
+# DO NOT USE
+# DO NOT USE
+#
+# This architecture / CPU variant must NOT be used for any 64 bit
+# platform builds. It is the lowest common denominator required
+# to build an unbundled application for all supported 32 and 64 bit
+# platforms.
+#
+# If you're building a 64 bit platform (and not an application) the
+# ARM-v8 specification allows you to assume NEON and all the features
+# available in a cortex-A15 CPU. You should be able to set :
+#
+# TARGET_2ND_ARCH_VARIANT := armv7-a-neon
+# TARGET_2ND_CPU_VARIANT := cortex-a15
+#
+# DO NOT USE
+# DO NOT USE
+TARGET_2ND_ARCH_VARIANT := armv7-a
+# DO NOT USE
+# DO NOT USE
+TARGET_2ND_CPU_VARIANT := generic
+# DO NOT USE
+# DO NOT USE
+else
+TARGET_2ND_ARCH_VARIANT := armv7-a-neon
+TARGET_2ND_CPU_VARIANT := cortex-a15
+endif
+
+
 TARGET_USES_64_BIT_BINDER := true
 
 # no hardware camera
@@ -48,7 +76,7 @@
 USE_OPENGL_RENDERER := true
 
 TARGET_USERIMAGES_USE_EXT4 := true
-BOARD_SYSTEMIMAGE_PARTITION_SIZE := 786432000
+BOARD_SYSTEMIMAGE_PARTITION_SIZE := 845427200
 BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800
 BOARD_CACHEIMAGE_PARTITION_SIZE := 69206016
 BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE := ext4
diff --git a/target/board/generic_arm64/device.mk b/target/board/generic_arm64/device.mk
index 733c83c..62dfa1b 100644
--- a/target/board/generic_arm64/device.mk
+++ b/target/board/generic_arm64/device.mk
@@ -25,6 +25,9 @@
 PRODUCT_COPY_FILES := \
     device/generic/goldfish/data/etc/apns-conf.xml:system/etc/apns-conf.xml \
     device/generic/goldfish/camera/media_profiles.xml:system/etc/media_profiles.xml \
+    frameworks/av/media/libstagefright/data/media_codecs_google_audio.xml:system/etc/media_codecs_google_audio.xml \
+    frameworks/av/media/libstagefright/data/media_codecs_google_telephony.xml:system/etc/media_codecs_google_telephony.xml \
+    frameworks/av/media/libstagefright/data/media_codecs_google_video.xml:system/etc/media_codecs_google_video.xml \
     device/generic/goldfish/camera/media_codecs.xml:system/etc/media_codecs.xml
 
 # The ranchu configuration files are needed to run under qemu-android
diff --git a/target/board/generic_mips/device.mk b/target/board/generic_mips/device.mk
index fe64bcb..06a7d8a 100644
--- a/target/board/generic_mips/device.mk
+++ b/target/board/generic_mips/device.mk
@@ -25,6 +25,9 @@
 PRODUCT_COPY_FILES := \
     device/generic/goldfish/data/etc/apns-conf.xml:system/etc/apns-conf.xml \
     device/generic/goldfish/camera/media_profiles.xml:system/etc/media_profiles.xml \
+    frameworks/av/media/libstagefright/data/media_codecs_google_audio.xml:system/etc/media_codecs_google_audio.xml \
+    frameworks/av/media/libstagefright/data/media_codecs_google_telephony.xml:system/etc/media_codecs_google_telephony.xml \
+    frameworks/av/media/libstagefright/data/media_codecs_google_video.xml:system/etc/media_codecs_google_video.xml \
     device/generic/goldfish/camera/media_codecs.xml:system/etc/media_codecs.xml \
     hardware/libhardware_legacy/audio/audio_policy.conf:system/etc/audio_policy.conf
 
diff --git a/target/board/generic_mips64/device.mk b/target/board/generic_mips64/device.mk
index aca8d24..66ec9db 100644
--- a/target/board/generic_mips64/device.mk
+++ b/target/board/generic_mips64/device.mk
@@ -25,6 +25,9 @@
 PRODUCT_COPY_FILES := \
     device/generic/goldfish/data/etc/apns-conf.xml:system/etc/apns-conf.xml \
     device/generic/goldfish/camera/media_profiles.xml:system/etc/media_profiles.xml \
+    frameworks/av/media/libstagefright/data/media_codecs_google_audio.xml:system/etc/media_codecs_google_audio.xml \
+    frameworks/av/media/libstagefright/data/media_codecs_google_telephony.xml:system/etc/media_codecs_google_telephony.xml \
+    frameworks/av/media/libstagefright/data/media_codecs_google_video.xml:system/etc/media_codecs_google_video.xml \
     device/generic/goldfish/camera/media_codecs.xml:system/etc/media_codecs.xml \
     hardware/libhardware_legacy/audio/audio_policy.conf:system/etc/audio_policy.conf
 
diff --git a/target/board/generic_x86/device.mk b/target/board/generic_x86/device.mk
index 089f584..b5b0faf 100644
--- a/target/board/generic_x86/device.mk
+++ b/target/board/generic_x86/device.mk
@@ -25,6 +25,9 @@
 PRODUCT_COPY_FILES := \
     device/generic/goldfish/data/etc/apns-conf.xml:system/etc/apns-conf.xml \
     device/generic/goldfish/camera/media_profiles.xml:system/etc/media_profiles.xml \
+    frameworks/av/media/libstagefright/data/media_codecs_google_audio.xml:system/etc/media_codecs_google_audio.xml \
+    frameworks/av/media/libstagefright/data/media_codecs_google_telephony.xml:system/etc/media_codecs_google_telephony.xml \
+    frameworks/av/media/libstagefright/data/media_codecs_google_video.xml:system/etc/media_codecs_google_video.xml \
     device/generic/goldfish/camera/media_codecs.xml:system/etc/media_codecs.xml
 
 PRODUCT_PACKAGES := \
diff --git a/target/board/generic_x86_64/BoardConfig.mk b/target/board/generic_x86_64/BoardConfig.mk
index c597f7d..c4fd958 100755
--- a/target/board/generic_x86_64/BoardConfig.mk
+++ b/target/board/generic_x86_64/BoardConfig.mk
@@ -41,7 +41,7 @@
 USE_OPENGL_RENDERER := true
 
 TARGET_USERIMAGES_USE_EXT4 := true
-BOARD_SYSTEMIMAGE_PARTITION_SIZE := 880803840 # 840M
+BOARD_SYSTEMIMAGE_PARTITION_SIZE := 943718400 # 900MB
 BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800
 BOARD_CACHEIMAGE_PARTITION_SIZE := 69206016
 BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE := ext4
diff --git a/target/board/generic_x86_64/device.mk b/target/board/generic_x86_64/device.mk
index 089f584..b5b0faf 100755
--- a/target/board/generic_x86_64/device.mk
+++ b/target/board/generic_x86_64/device.mk
@@ -25,6 +25,9 @@
 PRODUCT_COPY_FILES := \
     device/generic/goldfish/data/etc/apns-conf.xml:system/etc/apns-conf.xml \
     device/generic/goldfish/camera/media_profiles.xml:system/etc/media_profiles.xml \
+    frameworks/av/media/libstagefright/data/media_codecs_google_audio.xml:system/etc/media_codecs_google_audio.xml \
+    frameworks/av/media/libstagefright/data/media_codecs_google_telephony.xml:system/etc/media_codecs_google_telephony.xml \
+    frameworks/av/media/libstagefright/data/media_codecs_google_video.xml:system/etc/media_codecs_google_video.xml \
     device/generic/goldfish/camera/media_codecs.xml:system/etc/media_codecs.xml
 
 PRODUCT_PACKAGES := \
diff --git a/target/product/AndroidProducts.mk b/target/product/AndroidProducts.mk
index 97c5bda..ac5902c 100644
--- a/target/product/AndroidProducts.mk
+++ b/target/product/AndroidProducts.mk
@@ -42,7 +42,8 @@
     $(LOCAL_DIR)/aosp_mips.mk \
     $(LOCAL_DIR)/full_mips.mk \
     $(LOCAL_DIR)/aosp_arm64.mk \
-    $(LOCAL_DIR)/aosp_mips64.mk
+    $(LOCAL_DIR)/aosp_mips64.mk \
+    $(LOCAL_DIR)/aosp_x86_64.mk
 else
 PRODUCT_MAKEFILES := \
     $(LOCAL_DIR)/core.mk \
@@ -59,10 +60,15 @@
     $(LOCAL_DIR)/aosp_mips64.mk \
     $(LOCAL_DIR)/aosp_x86_64.mk \
     $(LOCAL_DIR)/full_x86_64.mk \
+    $(LOCAL_DIR)/sdk_phone_armv7.mk \
+    $(LOCAL_DIR)/sdk_phone_x86.mk \
+    $(LOCAL_DIR)/sdk_phone_mips.mk \
+    $(LOCAL_DIR)/sdk_phone_arm64.mk \
+    $(LOCAL_DIR)/sdk_phone_x86_64.mk \
+    $(LOCAL_DIR)/sdk_phone_mips64.mk \
     $(LOCAL_DIR)/sdk.mk \
     $(LOCAL_DIR)/sdk_x86.mk \
     $(LOCAL_DIR)/sdk_mips.mk \
     $(LOCAL_DIR)/sdk_arm64.mk \
-    $(LOCAL_DIR)/sdk_x86_64.mk \
-    $(LOCAL_DIR)/sdk_mips64.mk
+    $(LOCAL_DIR)/sdk_x86_64.mk
 endif
diff --git a/target/product/base.mk b/target/product/base.mk
index 8aa3bc0..4df10c4 100644
--- a/target/product/base.mk
+++ b/target/product/base.mk
@@ -18,6 +18,7 @@
 PRODUCT_PACKAGES += \
     20-dns.conf \
     95-configured \
+    appwidget \
     am \
     android.policy \
     android.test.runner \
@@ -30,8 +31,8 @@
     dhcpcd \
     dhcpcd-run-hooks \
     dnsmasq \
+    dpm \
     framework \
-    framework2 \
     fsck_msdos \
     ime \
     input \
@@ -41,24 +42,28 @@
     libandroid_servers \
     libaudioeffect_jni \
     libaudioflinger \
+    libaudiopolicyservice \
+    libaudiopolicymanager \
     libbundlewrapper \
     libcamera_client \
     libcameraservice \
     libdl \
+    libdrmclearkeyplugin \
     libeffectproxy \
     libeffects \
     libinput \
+    libinputflinger \
     libiprouteutil \
-    libjni_latinime \
     libjnigraphics \
     libldnhncr \
     libmedia \
     libmedia_jni \
     libmediaplayerservice \
     libmtp \
+    libnetd_client \
     libnetlink \
     libnetutils \
-    libpac \
+    libpdfium \
     libreference-ril \
     libreverbwrapper \
     libril \
@@ -67,6 +72,8 @@
     libskia \
     libsonivox \
     libsoundpool \
+    libsoundtrigger \
+    libsoundtriggerservice \
     libsqlite \
     libstagefright \
     libstagefright_amrnb_common \
@@ -79,6 +86,8 @@
     libutils \
     libvisualizer \
     libvorbisidec \
+    libmediandk \
+    libwifi-service \
     media \
     media_cmd \
     mediaserver \
@@ -95,7 +104,6 @@
     racoon \
     run-as \
     schedtest \
-    screenshot \
     sdcard \
     services \
     settings \
@@ -103,7 +111,6 @@
     tc \
     vdc \
     vold \
-    webview \
     wm
 
 
diff --git a/target/product/core.mk b/target/product/core.mk
index c5ef2aa..876a536 100644
--- a/target/product/core.mk
+++ b/target/product/core.mk
@@ -22,15 +22,36 @@
 PRODUCT_PACKAGES += \
     BasicDreams \
     Browser \
+    Calculator \
+    Calendar \
+    CalendarProvider \
+    CaptivePortalLogin \
+    CertInstaller \
     Contacts \
+    DeskClock \
     DocumentsUI \
     DownloadProviderUi \
+    Email \
+    Exchange2 \
     ExternalStorageProvider \
+    FusedLocation \
+    InputDevices \
     KeyChain \
+    Keyguard \
+    LatinIME \
+    Launcher2 \
+    ManagedProvisioning \
     PicoTts \
     PacProcessor \
+    libpac \
+    PrintSpooler \
     ProxyHandler \
+    QuickSearchBox \
+    Settings \
     SharedStorageBackup \
-    VpnDialogs
+    Telecom \
+    TeleService \
+    VpnDialogs \
+    MmsService
 
 $(call inherit-product, $(SRC_TARGET_DIR)/product/core_base.mk)
diff --git a/target/product/core_base.mk b/target/product/core_base.mk
index 26180da..6c29482 100644
--- a/target/product/core_base.mk
+++ b/target/product/core_base.mk
@@ -30,15 +30,12 @@
     libandroidfw \
     libaudiopreprocessing \
     libaudioutils \
-    libbcc \
     libfilterpack_imageproc \
     libgabi++ \
-    libkeystore \
     libmdnssd \
     libnfc_ndef \
     libpowermanager \
     libspeexresampler \
-    libstagefright_chromium_http \
     libstagefright_soft_aacdec \
     libstagefright_soft_aacenc \
     libstagefright_soft_amrdec \
@@ -49,9 +46,11 @@
     libstagefright_soft_gsmdec \
     libstagefright_soft_h264dec \
     libstagefright_soft_h264enc \
+    libstagefright_soft_hevcdec \
     libstagefright_soft_mp3dec \
     libstagefright_soft_mpeg4dec \
     libstagefright_soft_mpeg4enc \
+    libstagefright_soft_opusdec \
     libstagefright_soft_rawdec \
     libstagefright_soft_vorbisdec \
     libstagefright_soft_vpxdec \
@@ -59,25 +58,7 @@
     libvariablespeed \
     libwebrtc_audio_preprocessing \
     mdnsd \
-    mms-common \
     requestsync \
-    telephony-common \
-    voip-common
+    wifi-service
 
 $(call inherit-product, $(SRC_TARGET_DIR)/product/core_minimal.mk)
-# Override the PRODUCT_BOOT_JARS set in core_minimal.mk. The order matters.
-PRODUCT_BOOT_JARS := \
-    core-libart \
-    conscrypt \
-    okhttp \
-    core-junit \
-    bouncycastle \
-    ext \
-    framework \
-    framework2 \
-    telephony-common \
-    voip-common \
-    mms-common \
-    android.policy \
-    services \
-    apache-xml
diff --git a/target/product/core_minimal.mk b/target/product/core_minimal.mk
index 4b8b9ef..4c08cb0 100644
--- a/target/product/core_minimal.mk
+++ b/target/product/core_minimal.mk
@@ -32,33 +32,51 @@
     Shell \
     bcc \
     bu \
+    com.android.future.usb.accessory \
     com.android.location.provider \
     com.android.location.provider.xml \
     com.android.media.remotedisplay \
     com.android.media.remotedisplay.xml \
+    com.android.mediadrm.signer \
+    com.android.mediadrm.signer.xml \
     drmserver \
+    ethernet-service \
     framework-res \
     idmap \
     installd \
+    ims-common \
     ip \
     ip-up-vpn \
     ip6tables \
     iptables \
     keystore \
     keystore.default \
+    libbcc \
     libOpenMAXAL \
     libOpenSLES \
     libdownmix \
     libdrmframework \
     libdrmframework_jni \
     libfilterfw \
+    libkeystore \
     libsqlite_jni \
     libwilhelm \
     logd \
     make_ext4fs \
+    e2fsck \
+    resize2fs \
+    mms-common \
     screencap \
     sensorservice \
-    uiautomator
+    telephony-common \
+    uiautomator \
+    uncrypt \
+    voip-common \
+    webview \
+    wifi-service
+
+PRODUCT_COPY_FILES += \
+    frameworks/native/data/etc/android.software.webview.xml:system/etc/permissions/android.software.webview.xml
 
 # The order of PRODUCT_BOOT_JARS matters.
 PRODUCT_BOOT_JARS := \
@@ -69,10 +87,18 @@
     bouncycastle \
     ext \
     framework \
-    framework2 \
+    telephony-common \
+    voip-common \
+    ims-common \
+    mms-common \
     android.policy \
+    apache-xml \
+
+# The order of PRODUCT_SYSTEM_SERVER_JARS matters.
+PRODUCT_SYSTEM_SERVER_JARS := \
     services \
-    apache-xml
+    ethernet-service \
+    wifi-service
 
 PRODUCT_RUNTIMES := runtime_libart_default
 
diff --git a/target/product/core_tiny.mk b/target/product/core_tiny.mk
new file mode 100644
index 0000000..d6dbe98
--- /dev/null
+++ b/target/product/core_tiny.mk
@@ -0,0 +1,119 @@
+#
+# 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 \
+    CalendarProvider \
+    ContactsProvider \
+    CertInstaller \
+    FusedLocation \
+    InputDevices
+
+PRODUCT_PACKAGES += \
+    clatd \
+    clatd.conf \
+    pppd
+
+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 \
+    ims-common \
+    ip \
+    ip-up-vpn \
+    ip6tables \
+    iptables \
+    keystore \
+    keystore.default \
+    libOpenMAXAL \
+    libOpenSLES \
+    libdownmix \
+    libfilterfw \
+    libkeystore \
+    libsqlite_jni \
+    libwilhelm \
+    libdrmframework_jni \
+    libdrmframework \
+    make_ext4fs \
+    e2fsck \
+    resize2fs \
+    nullwebview \
+    screencap \
+    sensorservice \
+    uiautomator \
+    uncrypt \
+    telephony-common \
+    voip-common \
+    logd \
+    mms-common \
+    wifi-service
+
+# The order matters
+PRODUCT_BOOT_JARS := \
+    core-libart \
+    conscrypt \
+    okhttp \
+    core-junit \
+    bouncycastle \
+    ext \
+    framework \
+    telephony-common \
+    voip-common \
+    ims-common \
+    mms-common \
+    android.policy \
+    apache-xml \
+    nullwebview \
+
+# The order of PRODUCT_SYSTEM_SERVER_JARS matters.
+PRODUCT_SYSTEM_SERVER_JARS := \
+    services \
+    wifi-service
+
+PRODUCT_RUNTIMES := runtime_libart_default
+
+PRODUCT_DEFAULT_PROPERTY_OVERRIDES += \
+    ro.zygote=zygote32
+PRODUCT_COPY_FILES += \
+    system/core/rootdir/init.zygote32.rc:root/init.zygote32.rc
+
+PRODUCT_PROPERTY_OVERRIDES += \
+    ro.carrier=unknown
+
+$(call inherit-product, $(SRC_TARGET_DIR)/product/base.mk)
+$(call inherit-product-if-exists, frameworks/base/data/fonts/fonts.mk)
+
+# Overrides
+PRODUCT_BRAND := tiny
+PRODUCT_DEVICE := tiny
+PRODUCT_NAME := core_tiny
diff --git a/target/product/embedded.mk b/target/product/embedded.mk
index f815bbe..9f52336 100644
--- a/target/product/embedded.mk
+++ b/target/product/embedded.mk
@@ -20,6 +20,7 @@
 PRODUCT_PACKAGES += \
     adb \
     adbd \
+    atrace \
     bootanimation \
     debuggerd \
     dumpstate \
@@ -55,6 +56,7 @@
     libui \
     libutils \
     linker \
+    lmkd \
     logcat \
     logwrapper \
     mkshrc \
diff --git a/target/product/full_base.mk b/target/product/full_base.mk
index 059697e..9b1a826 100644
--- a/target/product/full_base.mk
+++ b/target/product/full_base.mk
@@ -22,11 +22,9 @@
 PRODUCT_PACKAGES := \
     libfwdlockengine \
     OpenWnn \
-    PinyinIME \
     libWnnEngDic \
     libWnnJpnDic \
     libwnndict \
-    VideoEditor \
     WAPPushManager
 
 PRODUCT_PACKAGES += \
diff --git a/target/product/full_base_telephony.mk b/target/product/full_base_telephony.mk
index f98e9a2..2fd2ce8 100644
--- a/target/product/full_base_telephony.mk
+++ b/target/product/full_base_telephony.mk
@@ -27,7 +27,8 @@
     ro.com.android.dataroaming=true
 
 PRODUCT_COPY_FILES := \
-    device/generic/goldfish/data/etc/apns-conf.xml:system/etc/apns-conf.xml
+    device/generic/goldfish/data/etc/apns-conf.xml:system/etc/apns-conf.xml \
+    frameworks/native/data/etc/handheld_core_hardware.xml:system/etc/permissions/handheld_core_hardware.xml
 
 $(call inherit-product, $(SRC_TARGET_DIR)/product/aosp_base.mk)
 $(call inherit-product, $(SRC_TARGET_DIR)/product/telephony.mk)
diff --git a/target/product/generic_no_telephony.mk b/target/product/generic_no_telephony.mk
index 5d9eee3..93c7563 100644
--- a/target/product/generic_no_telephony.mk
+++ b/target/product/generic_no_telephony.mk
@@ -17,33 +17,15 @@
 # This is a generic phone product that isn't specialized for a specific device.
 # It includes the base Android platform.
 
-PRODUCT_POLICY := android.policy_phone
-
 PRODUCT_PACKAGES := \
-    DeskClock \
     Bluetooth \
-    Calculator \
-    Calendar \
     Camera2 \
-    CertInstaller \
-    Email \
-    Exchange2 \
-    FusedLocation \
     Gallery2 \
-    InputDevices \
-    Keyguard \
-    LatinIME \
-    Launcher2 \
     Music \
     MusicFX \
     OneTimeInitializer \
-    PrintSpooler \
     Provision \
-    QuickSearchBox \
-    Settings \
     SystemUI \
-    TeleService \
-    CalendarProvider \
     WallpaperCropper
 
 PRODUCT_PACKAGES += \
@@ -82,7 +64,6 @@
 $(call inherit-product-if-exists, external/google-fonts/coming-soon/fonts.mk)
 $(call inherit-product-if-exists, external/noto-fonts/fonts.mk)
 $(call inherit-product-if-exists, external/naver-fonts/fonts.mk)
-$(call inherit-product-if-exists, external/sil-fonts/fonts.mk)
 $(call inherit-product-if-exists, frameworks/base/data/keyboards/keyboards.mk)
 $(call inherit-product-if-exists, frameworks/webview/chromium/chromium.mk)
 $(call inherit-product, $(SRC_TARGET_DIR)/product/core.mk)
diff --git a/target/product/languages_full.mk b/target/product/languages_full.mk
index 4cddc06..030777e 100644
--- a/target/product/languages_full.mk
+++ b/target/product/languages_full.mk
@@ -21,4 +21,4 @@
 
 # These are all the locales that have translations and are displayable
 # by TextView in this branch.
-PRODUCT_LOCALES := en_US en_IN fr_FR it_IT es_ES et_EE de_DE nl_NL cs_CZ pl_PL ja_JP zh_TW zh_CN zh_HK ru_RU ko_KR nb_NO es_US da_DK el_GR tr_TR pt_PT pt_BR rm_CH sv_SE bg_BG ca_ES en_GB fi_FI hi_IN hr_HR hu_HU in_ID iw_IL lt_LT lv_LV ro_RO sk_SK sl_SI sr_RS uk_UA vi_VN tl_PH ar_EG fa_IR th_TH sw_TZ ms_MY af_ZA zu_ZA am_ET hi_IN en_XA ar_XB fr_CA km_KH lo_LA ne_NP si_LK mn_MN hy_AM az_AZ ka_GE
+PRODUCT_LOCALES := en_AU en_US en_IN fr_FR it_IT es_ES et_EE de_DE nl_NL cs_CZ pl_PL ja_JP zh_TW zh_CN zh_HK ru_RU ko_KR nb_NO es_US da_DK el_GR tr_TR pt_PT pt_BR rm_CH sv_SE bg_BG ca_ES en_GB fi_FI hi_IN hr_HR hu_HU in_ID iw_IL lt_LT lv_LV ro_RO sk_SK sl_SI sr_RS uk_UA vi_VN tl_PH ar_EG fa_IR th_TH sw_TZ ms_MY af_ZA zu_ZA am_ET hi_IN en_XA ar_XB fr_CA km_KH lo_LA ne_NP si_LK mn_MN hy_AM az_AZ ka_GE my_MM mr_IN ml_IN is_IS mk_MK ky_KG eu_ES gl_ES bn_BD ta_IN kn_IN te_IN uz_UZ ur_PK kk_KZ
diff --git a/target/product/sdk.mk b/target/product/sdk.mk
index 04157e8..96d8cc9 100644
--- a/target/product/sdk.mk
+++ b/target/product/sdk.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2007 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,170 +14,8 @@
 # limitations under the License.
 #
 
-PRODUCT_POLICY := android.policy_phone
-PRODUCT_PROPERTY_OVERRIDES :=
+# Don't modify this file - It's just an alias!
 
-PRODUCT_PACKAGES := \
-	Calculator \
-	DeskClock \
-	Email \
-	Exchange2 \
-	FusedLocation \
-	Gallery \
-	Keyguard \
-	Music \
-	Mms \
-	OpenWnn \
-	PrintSpooler \
-	libWnnEngDic \
-	libWnnJpnDic \
-	libwnndict \
-	TeleService \
-	PinyinIME \
-	Protips \
-	SoftKeyboard \
-	SystemUI \
-	Launcher2 \
-	Development \
-	DevelopmentSettings \
-	Fallback \
-	Settings \
-	SdkSetup \
-	CustomLocale \
-	sqlite3 \
-	InputDevices \
-	LatinIME \
-	CertInstaller \
-	LiveWallpapersPicker \
-	ApiDemos \
-	GestureBuilder \
-	CubeLiveWallpapers \
-	QuickSearchBox \
-	WidgetPreview \
-	librs_jni \
-	CalendarProvider \
-	Calendar \
-	SmokeTest \
-	SmokeTestApp \
-	EmulatorSmokeTests \
-	rild \
-	LegacyCamera \
-	Dialer
+$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk_phone_armv7.mk)
 
-
-# Define the host tools and libs that are parts of the SDK.
--include sdk/build/product_sdk.mk
--include development/build/product_sdk.mk
-
-# audio libraries.
-PRODUCT_PACKAGES += \
-	audio.primary.goldfish \
-	audio_policy.default \
-	local_time.default
-
-PRODUCT_PACKAGE_OVERLAYS := development/sdk_overlay
-
-PRODUCT_COPY_FILES := \
-	device/generic/goldfish/data/etc/apns-conf.xml:system/etc/apns-conf.xml \
-	frameworks/base/data/sounds/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
-	frameworks/base/data/sounds/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
-	frameworks/native/data/etc/handheld_core_hardware.xml:system/etc/permissions/handheld_core_hardware.xml \
-	device/generic/goldfish/camera/media_profiles.xml:system/etc/media_profiles.xml \
-	device/generic/goldfish/camera/media_codecs.xml:system/etc/media_codecs.xml \
-	frameworks/native/data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml:system/etc/permissions/android.hardware.touchscreen.multitouch.jazzhand.xml \
-	frameworks/native/data/etc/android.hardware.camera.autofocus.xml:system/etc/permissions/android.hardware.camera.autofocus.xml \
-	frameworks/av/media/libeffects/data/audio_effects.conf:system/etc/audio_effects.conf \
-	hardware/libhardware_legacy/audio/audio_policy.conf:system/etc/audio_policy.conf
-
-include $(SRC_TARGET_DIR)/product/emulator.mk
-
-$(call inherit-product-if-exists, frameworks/base/data/sounds/AllAudio.mk)
-$(call inherit-product-if-exists, frameworks/base/data/fonts/fonts.mk)
-$(call inherit-product-if-exists, external/google-fonts/dancing-script/fonts.mk)
-$(call inherit-product-if-exists, external/google-fonts/carrois-gothic-sc/fonts.mk)
-$(call inherit-product-if-exists, external/google-fonts/coming-soon/fonts.mk)
-$(call inherit-product-if-exists, external/noto-fonts/fonts.mk)
-$(call inherit-product-if-exists, external/naver-fonts/fonts.mk)
-$(call inherit-product-if-exists, external/sil-fonts/fonts.mk)
-$(call inherit-product-if-exists, frameworks/base/data/keyboards/keyboards.mk)
-$(call inherit-product-if-exists, frameworks/webview/chromium/chromium.mk)
-$(call inherit-product, $(SRC_TARGET_DIR)/product/core.mk)
-
-# Overrides
-PRODUCT_BRAND := generic
 PRODUCT_NAME := sdk
-PRODUCT_DEVICE := generic
-
-# locale + densities. en_US is both first and in alphabetical order to
-# ensure this is the default locale.
-PRODUCT_LOCALES = \
-	en_US \
-	ldpi \
-	hdpi \
-	mdpi \
-	xhdpi \
-	ar_EG \
-	ar_IL \
-	bg_BG \
-	ca_ES \
-	cs_CZ \
-	da_DK \
-	de_AT \
-	de_CH \
-	de_DE \
-	de_LI \
-	el_GR \
-	en_AU \
-	en_CA \
-	en_GB \
-	en_IE \
-	en_IN \
-	en_NZ \
-	en_SG \
-	en_US \
-	en_ZA \
-	es_ES \
-	es_US \
-	fi_FI \
-	fr_BE \
-	fr_CA \
-	fr_CH \
-	fr_FR \
-	he_IL \
-	hi_IN \
-	hr_HR \
-	hu_HU \
-	id_ID \
-	it_CH \
-	it_IT \
-	ja_JP \
-	ko_KR \
-	lt_LT \
-	lv_LV \
-	nb_NO \
-	nl_BE \
-	nl_NL \
-	pl_PL \
-	pt_BR \
-	pt_PT \
-	ro_RO \
-	ru_RU \
-	sk_SK \
-	sl_SI \
-	sr_RS \
-	sv_SE \
-	th_TH \
-	tl_PH \
-	tr_TR \
-	uk_UA \
-	vi_VN \
-	zh_CN \
-	zh_TW
-
-# include available languages for TTS in the system image
--include external/svox/pico/lang/PicoLangDeDeInSystem.mk
--include external/svox/pico/lang/PicoLangEnGBInSystem.mk
--include external/svox/pico/lang/PicoLangEnUsInSystem.mk
--include external/svox/pico/lang/PicoLangEsEsInSystem.mk
--include external/svox/pico/lang/PicoLangFrFrInSystem.mk
--include external/svox/pico/lang/PicoLangItItInSystem.mk
diff --git a/target/product/sdk_arm64.mk b/target/product/sdk_arm64.mk
index d724207..8bb38f4 100644
--- a/target/product/sdk_arm64.mk
+++ b/target/product/sdk_arm64.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2009 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,17 +14,8 @@
 # limitations under the License.
 #
 
-# This is a build configuration for a full-featured build of the
-# Open-Source part of the tree. It's geared toward a US-centric
-# build quite specifically for the emulator, and might not be
-# entirely appropriate to inherit from for on-device configurations.
+# Don't modify this file - It's just an alias!
 
-$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
-$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk.mk)
-$(call inherit-product, $(SRC_TARGET_DIR)/board/generic_arm64/device.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk_phone_arm64.mk)
 
-# Overrides
-PRODUCT_BRAND := generic_arm64
 PRODUCT_NAME := sdk_arm64
-PRODUCT_DEVICE := generic_arm64
-PRODUCT_MODEL := Android SDK built for arm64
diff --git a/target/product/sdk_base.mk b/target/product/sdk_base.mk
new file mode 100644
index 0000000..56eace5
--- /dev/null
+++ b/target/product/sdk_base.mk
@@ -0,0 +1,161 @@
+#
+# 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.
+#
+
+PRODUCT_PROPERTY_OVERRIDES :=
+
+PRODUCT_PACKAGES := \
+	ApiDemos \
+	CubeLiveWallpapers \
+	CustomLocale \
+	Development \
+	DevelopmentSettings \
+	Dialer \
+	EmulatorSmokeTests \
+	Fallback \
+	Gallery \
+	GestureBuilder \
+	LegacyCamera \
+	librs_jni \
+	libwnndict \
+	libWnnEngDic \
+	libWnnJpnDic \
+	LiveWallpapersPicker \
+	Mms \
+	Music \
+	OpenWnn \
+	Protips \
+	rild \
+	SdkSetup \
+	SmokeTest \
+	SmokeTestApp \
+	SoftKeyboard \
+	sqlite3 \
+	SystemUI \
+	WidgetPreview
+
+# Define the host tools and libs that are parts of the SDK.
+-include sdk/build/product_sdk.mk
+-include development/build/product_sdk.mk
+
+# audio libraries.
+PRODUCT_PACKAGES += \
+	audio.primary.goldfish \
+	audio_policy.default \
+	local_time.default
+
+PRODUCT_PACKAGE_OVERLAYS := development/sdk_overlay
+
+PRODUCT_COPY_FILES := \
+	device/generic/goldfish/data/etc/apns-conf.xml:system/etc/apns-conf.xml \
+	frameworks/base/data/sounds/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
+	frameworks/base/data/sounds/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
+	frameworks/native/data/etc/handheld_core_hardware.xml:system/etc/permissions/handheld_core_hardware.xml \
+	device/generic/goldfish/camera/media_profiles.xml:system/etc/media_profiles.xml \
+	frameworks/av/media/libstagefright/data/media_codecs_google_audio.xml:system/etc/media_codecs_google_audio.xml \
+	frameworks/av/media/libstagefright/data/media_codecs_google_telephony.xml:system/etc/media_codecs_google_telephony.xml \
+	frameworks/av/media/libstagefright/data/media_codecs_google_video.xml:system/etc/media_codecs_google_video.xml \
+	device/generic/goldfish/camera/media_codecs.xml:system/etc/media_codecs.xml \
+	frameworks/native/data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml:system/etc/permissions/android.hardware.touchscreen.multitouch.jazzhand.xml \
+	frameworks/native/data/etc/android.hardware.camera.autofocus.xml:system/etc/permissions/android.hardware.camera.autofocus.xml \
+	frameworks/av/media/libeffects/data/audio_effects.conf:system/etc/audio_effects.conf \
+	hardware/libhardware_legacy/audio/audio_policy.conf:system/etc/audio_policy.conf
+
+include $(SRC_TARGET_DIR)/product/emulator.mk
+
+$(call inherit-product-if-exists, frameworks/base/data/sounds/AllAudio.mk)
+$(call inherit-product-if-exists, frameworks/base/data/fonts/fonts.mk)
+$(call inherit-product-if-exists, external/google-fonts/dancing-script/fonts.mk)
+$(call inherit-product-if-exists, external/google-fonts/carrois-gothic-sc/fonts.mk)
+$(call inherit-product-if-exists, external/google-fonts/coming-soon/fonts.mk)
+$(call inherit-product-if-exists, external/noto-fonts/fonts.mk)
+$(call inherit-product-if-exists, external/naver-fonts/fonts.mk)
+$(call inherit-product-if-exists, frameworks/base/data/keyboards/keyboards.mk)
+$(call inherit-product-if-exists, frameworks/webview/chromium/chromium.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/core.mk)
+
+# include available languages for TTS in the system image
+-include external/svox/pico/lang/PicoLangDeDeInSystem.mk
+-include external/svox/pico/lang/PicoLangEnGBInSystem.mk
+-include external/svox/pico/lang/PicoLangEnUsInSystem.mk
+-include external/svox/pico/lang/PicoLangEsEsInSystem.mk
+-include external/svox/pico/lang/PicoLangFrFrInSystem.mk
+-include external/svox/pico/lang/PicoLangItItInSystem.mk
+
+# locale + densities. en_US is both first and in alphabetical order to
+# ensure this is the default locale.
+PRODUCT_LOCALES := \
+	en_US \
+	ldpi \
+	hdpi \
+	mdpi \
+	xhdpi \
+	ar_EG \
+	ar_IL \
+	bg_BG \
+	ca_ES \
+	cs_CZ \
+	da_DK \
+	de_AT \
+	de_CH \
+	de_DE \
+	de_LI \
+	el_GR \
+	en_AU \
+	en_CA \
+	en_GB \
+	en_IE \
+	en_IN \
+	en_NZ \
+	en_SG \
+	en_US \
+	en_ZA \
+	es_ES \
+	es_US \
+	fi_FI \
+	fr_BE \
+	fr_CA \
+	fr_CH \
+	fr_FR \
+	he_IL \
+	hi_IN \
+	hr_HR \
+	hu_HU \
+	id_ID \
+	it_CH \
+	it_IT \
+	ja_JP \
+	ko_KR \
+	lt_LT \
+	lv_LV \
+	nb_NO \
+	nl_BE \
+	nl_NL \
+	pl_PL \
+	pt_BR \
+	pt_PT \
+	ro_RO \
+	ru_RU \
+	sk_SK \
+	sl_SI \
+	sr_RS \
+	sv_SE \
+	th_TH \
+	tl_PH \
+	tr_TR \
+	uk_UA \
+	vi_VN \
+	zh_CN \
+	zh_TW
diff --git a/target/product/sdk_mips.mk b/target/product/sdk_mips.mk
index 2072400..366994a 100644
--- a/target/product/sdk_mips.mk
+++ b/target/product/sdk_mips.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2012 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,15 +14,8 @@
 # limitations under the License.
 #
 
-# This is a build configuration for a full-featured build of the
-# Open-Source part of the tree. It's geared toward a US-centric
-# build quite specifically for the emulator, and might not be
-# entirely appropriate to inherit from for on-device configurations.
+# Don't modify this file - It's just an alias!
 
-$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk_phone_mips.mk)
 
-# Overrides
-PRODUCT_BRAND := generic_mips
 PRODUCT_NAME := sdk_mips
-PRODUCT_DEVICE := generic_mips
-PRODUCT_MODEL := Android SDK for Mips
diff --git a/target/product/sdk_mips64.mk b/target/product/sdk_phone_arm64.mk
similarity index 77%
copy from target/product/sdk_mips64.mk
copy to target/product/sdk_phone_arm64.mk
index c46eaed..a0cf6c1 100644
--- a/target/product/sdk_mips64.mk
+++ b/target/product/sdk_phone_arm64.mk
@@ -20,10 +20,11 @@
 # entirely appropriate to inherit from for on-device configurations.
 
 $(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
-$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk_base.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/board/generic_arm64/device.mk)
 
 # Overrides
-PRODUCT_BRAND := generic_mips64
-PRODUCT_NAME := sdk_mips64
-PRODUCT_DEVICE := generic_mips64
-PRODUCT_MODEL := Android SDK built for mips64
+PRODUCT_BRAND := generic_arm64
+PRODUCT_NAME := sdk_phone_arm64
+PRODUCT_DEVICE := generic_arm64
+PRODUCT_MODEL := Android SDK built for arm64
diff --git a/target/product/sdk_phone_armv7.mk b/target/product/sdk_phone_armv7.mk
new file mode 100644
index 0000000..aeb4940
--- /dev/null
+++ b/target/product/sdk_phone_armv7.mk
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk_base.mk)
+
+# Overrides
+PRODUCT_BRAND := generic
+PRODUCT_NAME := sdk_phone_armv7
+PRODUCT_DEVICE := generic
diff --git a/target/product/sdk_mips64.mk b/target/product/sdk_phone_mips.mk
similarity index 72%
copy from target/product/sdk_mips64.mk
copy to target/product/sdk_phone_mips.mk
index c46eaed..818491f 100644
--- a/target/product/sdk_mips64.mk
+++ b/target/product/sdk_phone_mips.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2009 The Android Open Source Project
+# 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.
@@ -19,11 +19,10 @@
 # build quite specifically for the emulator, and might not be
 # entirely appropriate to inherit from for on-device configurations.
 
-$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
-$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk_base.mk)
 
 # Overrides
-PRODUCT_BRAND := generic_mips64
-PRODUCT_NAME := sdk_mips64
-PRODUCT_DEVICE := generic_mips64
-PRODUCT_MODEL := Android SDK built for mips64
+PRODUCT_BRAND := generic_mips
+PRODUCT_NAME := sdk_phone_mips
+PRODUCT_DEVICE := generic_mips
+PRODUCT_MODEL := Android SDK for Mips
diff --git a/target/product/sdk_mips64.mk b/target/product/sdk_phone_mips64.mk
similarity index 91%
rename from target/product/sdk_mips64.mk
rename to target/product/sdk_phone_mips64.mk
index c46eaed..afdb2a8 100644
--- a/target/product/sdk_mips64.mk
+++ b/target/product/sdk_phone_mips64.mk
@@ -20,10 +20,10 @@
 # entirely appropriate to inherit from for on-device configurations.
 
 $(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
-$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk_base.mk)
 
 # Overrides
 PRODUCT_BRAND := generic_mips64
-PRODUCT_NAME := sdk_mips64
+PRODUCT_NAME := sdk_phone_mips64
 PRODUCT_DEVICE := generic_mips64
 PRODUCT_MODEL := Android SDK built for mips64
diff --git a/target/product/sdk_mips64.mk b/target/product/sdk_phone_x86.mk
similarity index 76%
copy from target/product/sdk_mips64.mk
copy to target/product/sdk_phone_x86.mk
index c46eaed..95c49ab 100644
--- a/target/product/sdk_mips64.mk
+++ b/target/product/sdk_phone_x86.mk
@@ -19,11 +19,10 @@
 # build quite specifically for the emulator, and might not be
 # entirely appropriate to inherit from for on-device configurations.
 
-$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
-$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk_base.mk)
 
 # Overrides
-PRODUCT_BRAND := generic_mips64
-PRODUCT_NAME := sdk_mips64
-PRODUCT_DEVICE := generic_mips64
-PRODUCT_MODEL := Android SDK built for mips64
+PRODUCT_BRAND := generic_x86
+PRODUCT_NAME := sdk_phone_x86
+PRODUCT_DEVICE := generic_x86
+PRODUCT_MODEL := Android SDK built for x86
diff --git a/target/product/sdk_mips64.mk b/target/product/sdk_phone_x86_64.mk
similarity index 81%
copy from target/product/sdk_mips64.mk
copy to target/product/sdk_phone_x86_64.mk
index c46eaed..69e37af 100644
--- a/target/product/sdk_mips64.mk
+++ b/target/product/sdk_phone_x86_64.mk
@@ -20,10 +20,10 @@
 # entirely appropriate to inherit from for on-device configurations.
 
 $(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
-$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk_base.mk)
 
 # Overrides
-PRODUCT_BRAND := generic_mips64
-PRODUCT_NAME := sdk_mips64
-PRODUCT_DEVICE := generic_mips64
-PRODUCT_MODEL := Android SDK built for mips64
+PRODUCT_BRAND := generic_x86_64
+PRODUCT_NAME := sdk_phone_x86_64
+PRODUCT_DEVICE := generic_x86_64
+PRODUCT_MODEL := Android SDK built for x86_64
diff --git a/target/product/sdk_x86.mk b/target/product/sdk_x86.mk
index 873d0c0..13ee57d 100644
--- a/target/product/sdk_x86.mk
+++ b/target/product/sdk_x86.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2009 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,15 +14,8 @@
 # limitations under the License.
 #
 
-# This is a build configuration for a full-featured build of the
-# Open-Source part of the tree. It's geared toward a US-centric
-# build quite specifically for the emulator, and might not be
-# entirely appropriate to inherit from for on-device configurations.
+# Don't modify this file - It's just an alias!
 
-include $(SRC_TARGET_DIR)/product/sdk.mk
+$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk_phone_x86.mk)
 
-# Overrides
-PRODUCT_BRAND := generic_x86
 PRODUCT_NAME := sdk_x86
-PRODUCT_DEVICE := generic_x86
-PRODUCT_MODEL := Android SDK built for x86
diff --git a/target/product/sdk_x86_64.mk b/target/product/sdk_x86_64.mk
index 62f2dbb..5f6553e 100644
--- a/target/product/sdk_x86_64.mk
+++ b/target/product/sdk_x86_64.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2009 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,16 +14,8 @@
 # limitations under the License.
 #
 
-# This is a build configuration for a full-featured build of the
-# Open-Source part of the tree. It's geared toward a US-centric
-# build quite specifically for the emulator, and might not be
-# entirely appropriate to inherit from for on-device configurations.
+# Don't modify this file - It's just an alias!
 
-$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
-$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk_phone_x86_64.mk)
 
-# Overrides
-PRODUCT_BRAND := generic_x86_64
 PRODUCT_NAME := sdk_x86_64
-PRODUCT_DEVICE := generic_x86_64
-PRODUCT_MODEL := Android SDK built for x86_64
diff --git a/target/product/security/Android.mk b/target/product/security/Android.mk
new file mode 100644
index 0000000..5a40397
--- /dev/null
+++ b/target/product/security/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+
+#######################################
+# verity_key
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := verity_key
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
+
+include $(BUILD_PREBUILT)
diff --git a/target/product/security/verity_key b/target/product/security/verity_key
new file mode 100644
index 0000000..8db965f
--- /dev/null
+++ b/target/product/security/verity_key
Binary files differ
diff --git a/target/product/security/verity_private_dev_key b/target/product/security/verity_private_dev_key
new file mode 100644
index 0000000..92528e9
--- /dev/null
+++ b/target/product/security/verity_private_dev_key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDQxdVrH2RB1eg5
+17/gBmLzW1Ds10RG6ctNZMhxppMOLnEZViKGv1VNRhxqK/JKTv2UujgZ94SJcDub
+G+DwAwaGZKQqDYUa0VU2cng8TYPcnYGPdJ7Usckp6tdg64vns7e+VVf0dOyEovR+
+JyeYUz05OhUMYP9xJIhpA2XnXe5Ekb9iTFSYo9uBpoXDD4IY7aOqUxSbv9wMtyIp
+dl+oTm0+kqRRi4KoxGHV0CzDseEUuWG/Kp/7aVF9Sg45NcC6KYvrGysUKA+Bt09O
+feDn/HRpT9SfRElJa5DRms33UBUtnom15F4yd4vvFgubB0nkPOUuwfZhTFfgeuY4
+H2bHkjKbAgMBAAECggEAMpFYqkPGQvQO9cO+ZALoAM4Dgfp6PTrv1WUt7+lLAUpa
+dqqYXk8F2Fu9EjJm03ziix237QI5Bhk7Nsy/5SK2d+L0qILx1JcTrsZ3PRQBdnRo
+J1k2B4qwkQii9oTXNF4hiWaekUWo7E+ULOJLAuhWkf/xjTgJZ1xT9iuuiSYFSnIa
+9ABNH0vCaKEkW/4ri6fdtXmO26C/ltJlnozl86x07PIFh4uBas7/40E8ykFP00CS
+zdhMh+2DGyCb1Q0eJ1IfGILNatkLNEd2BHgQ7qNBkN9yShZfhvIPblr5gSUlZplX
+diV20ZGLAfByKWgZZWKkwl9KzaisL/J/4dr2UlSVEQKBgQDxAYTsgoTkkP0TKzr3
+i3ljT8OuVOj6TwZVBJYe2MIJ3veivS3gWB53FpsKthbib7y8ifIakn15mQkNCK5R
+7H7F5lvZCNnB6shY5Dz7nLJxKLALcAg+d12l3gTbFQeFDs0iQQJF7P8hs/GPF7kY
+Layb7EF0uzYjyHJCKtFdaZaeZwKBgQDdwvCb7NJVeGTcE97etL+8acu9y4GlqKEF
+o0Vkw8TjNKj/KuDkbkAk9hXxU1ZCmDU3y6r8CVHYl0Sqh08plEhkYB/j3sFy81zY
+3xu/rLFysBwjeJHHlPjRTYkdKr9pABmm8NIEShvu9u8i+mpOhjbX72HxZL+i4Fou
+gz58wEdBrQKBgG8CfyKdn+7UJe3tbLTXRquK8xxauhGJ0uXYPfmpZ/8596C7OOVs
+UWQTQoj1hKb6RtolRCIfNbKL3hJl3D2aDG7Fg6r9m6fpqCzhvIE9FShwUF6EVRfI
+zZb4JA5xqkwMnEpZ3V0uI/p3Mx3xFG3ho+8SLLhC/1YOHysBI/y+BQWjAoGAYiqQ
+PkXYWhOAeleleeqDUdF3al3y1zVNimRbLJ7owjcmdEYz5YrUhEgXMIvWjIY6UKes
+2gL6IynbMK3TIjHM1fojQ8jw04TdXfdtnizBJGbHHgCab8IHXwe2oZ2xu7ZapKbI
+ITP5J5BSDabSdk49attB/Qy/NEeiRCK+/5RSNsUCgYAg6vX9VqMEkhPHeoFfdLGD
+EQPPN6QLrQ4Zif0GKxH96znNSv0rXdNp9t0kyapdgzMuCwIEuOkCSiKgmfjTWnYO
+qh5HMUuD2VbfWwI9jVujQMRmqiaFF7VxxA1bP5j1hJlI6cn1Fjlpi+NsNZN4nm3Q
+92SEwX2vDgjrU0NAtFFL1Q==
+-----END PRIVATE KEY-----
diff --git a/target/product/verity.mk b/target/product/verity.mk
new file mode 100644
index 0000000..4a1ca5e
--- /dev/null
+++ b/target/product/verity.mk
@@ -0,0 +1,23 @@
+#
+# 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.
+#
+
+# Provides dependencies necessary for verified boot
+
+PRODUCT_SUPPORTS_VERITY := true
+PRODUCT_VERITY_SIGNING_KEY := build/target/product/security/verity_private_dev_key
+
+PRODUCT_PACKAGES += \
+        verity_key
diff --git a/tools/atree/atree.cpp b/tools/atree/atree.cpp
index 2ba284f..b134e01 100644
--- a/tools/atree/atree.cpp
+++ b/tools/atree/atree.cpp
@@ -90,6 +90,26 @@
     }
 }
 
+// Escape the filename so that it can be added to the makefile properly.
+static string
+escape_filename(const string name)
+{
+    ostringstream new_name;
+    for (string::const_iterator iter = name.begin(); iter != name.end(); ++iter)
+    {
+        switch (*iter)
+        {
+            case '$':
+                new_name << "$$";
+                break;
+            default:
+                new_name << *iter;
+                break;
+        }
+    }
+    return new_name.str();
+}
+
 int
 main(int argc, char* const* argv)
 {
@@ -324,7 +344,8 @@
             for (vector<FileRecord>::iterator it=files.begin();
                                 it!=files.end(); it++) {
                 if (!it->sourceIsDir) {
-                    fprintf(f, "%s \\\n", it->sourcePath.c_str());
+                    fprintf(f, "%s \\\n",
+                            escape_filename(it->sourcePath).c_str());
                 }
             }
             fprintf(f, "\n");
diff --git a/tools/buildinfo.sh b/tools/buildinfo.sh
index 46a73f8..593e5b5 100755
--- a/tools/buildinfo.sh
+++ b/tools/buildinfo.sh
@@ -8,6 +8,7 @@
 echo "ro.build.version.incremental=$BUILD_NUMBER"
 echo "ro.build.version.sdk=$PLATFORM_SDK_VERSION"
 echo "ro.build.version.codename=$PLATFORM_VERSION_CODENAME"
+echo "ro.build.version.all_codenames=$PLATFORM_VERSION_ALL_CODENAMES"
 echo "ro.build.version.release=$PLATFORM_VERSION"
 echo "ro.build.date=`date`"
 echo "ro.build.date.utc=`date +%s`"
@@ -46,9 +47,10 @@
 echo "# ro.build.product is obsolete; use ro.product.device"
 echo "ro.build.product=$TARGET_DEVICE"
 
-echo "# Do not try to parse ro.build.description or .fingerprint"
+echo "# Do not try to parse description, fingerprint, or thumbprint"
 echo "ro.build.description=$PRIVATE_BUILD_DESC"
 echo "ro.build.fingerprint=$BUILD_FINGERPRINT"
+echo "ro.build.thumbprint=$BUILD_THUMBPRINT"
 echo "ro.build.characteristics=$TARGET_AAPT_CHARACTERISTICS"
 
 echo "# end build properties"
diff --git a/tools/droiddoc/templates-ds/package.cs b/tools/droiddoc/templates-ds/package.cs
index ea3e4f4..d67d5d9 100644
--- a/tools/droiddoc/templates-ds/package.cs
+++ b/tools/droiddoc/templates-ds/package.cs
@@ -45,6 +45,7 @@
   <?cs /if ?>
 <?cs /def ?>
 
+<?cs call:class_table("Annotations", package.annotations) ?>
 <?cs call:class_table("Interfaces", package.interfaces) ?>
 <?cs call:class_table("Classes", package.classes) ?>
 <?cs call:class_table("Enums", package.enums) ?>
diff --git a/tools/droiddoc/templates-sac/package.cs b/tools/droiddoc/templates-sac/package.cs
index 99eaff2..abd49f1 100644
--- a/tools/droiddoc/templates-sac/package.cs
+++ b/tools/droiddoc/templates-sac/package.cs
@@ -45,6 +45,7 @@
   <?cs /if ?>
 <?cs /def ?>
 
+<?cs call:class_table("Annotations", package.annotations) ?>
 <?cs call:class_table("Interfaces", package.interfaces) ?>
 <?cs call:class_table("Classes", package.classes) ?>
 <?cs call:class_table("Enums", package.enums) ?>
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/css/default.css b/tools/droiddoc/templates-sdk-dyn/assets/css/default.css
index 7515360..e26aec6 100644
--- a/tools/droiddoc/templates-sdk-dyn/assets/css/default.css
+++ b/tools/droiddoc/templates-sdk-dyn/assets/css/default.css
@@ -98,7 +98,8 @@
 #devdoc-nav.fixed {
   position: fixed;
   margin:0;
-  top: 20px; }
+  top: 65px; /* sticky-header height + 20px gutter */
+}
 
 #devdoc-nav span.small {
   font-size:12px;
@@ -358,6 +359,19 @@
   #nav li span.tree-list-subtitle:after {
     content: '—';
   }
+  #nav li span.tree-list-subtitle.package {
+    padding-top:15px;
+    cursor:default;
+  }
+  #nav li span.tree-list-subtitle.package:before {
+    content: '';
+  }
+  #nav li span.tree-list-subtitle.package:after {
+    content: '';
+  }
+  #nav li ul.tree-list-children.classes {
+    padding-left:10px;
+  }
   #nav li ul {
     display:none;
     overflow: hidden;
@@ -1365,8 +1379,7 @@
   .training-nav-top, .training-nav-bottom,
   #doc-col .content-footer,
   .nav-x, .nav-y,
-  .paging-links,
-  a.totop {
+  .paging-links {
       display: none !important;
   }
 
@@ -1491,7 +1504,8 @@
 Header, Login, Nav-X, Search
 */
 #header {
-  padding: 2.2em 0 0.2em 0;
+  margin: 0;
+  padding: 0;
 }
 #header:before, #header:after {
   content: "";
@@ -1828,8 +1842,8 @@
 #qv-wrapper {
   float:right;
   clear:right;
-  margin:0 0 0 20px; /* negative top-margin to counter the content-header bottom margin */
-  padding:0 0 20px;
+  margin:0 0 0 30px; /* negative top-margin to counter the content-header bottom margin */
+  padding:0 0 30px;
 }
 
 #tb-wrapper {
@@ -2871,26 +2885,6 @@
   margin:0 0 10px;
 }
 
-#devdoc-nav a.totop {
-  display:block;
-  top:0;
-  width:inherit;
-  background: transparent url(../images/styles/gototop.png) no-repeat scroll 50% 50%;
-  text-indent:-9999em;
-}
-#devdoc-nav a.totop {
-  position:fixed;
-  display:none;
-}
-#devdoc-nav a.totop:hover {
-  background-color:#33B5E5;
-}
-
-.content-footer a.totop {
-  text-transform:uppercase;
-  line-height:30px;
-}
-
 .expandable {
   height:34px;
   padding-left:20px;
@@ -3955,13 +3949,174 @@
   z-index:100;
 }
 
+
+
+
+
+/************ STICKY NAV BAR ******************/
+
+#header-wrapper {
+  background: #f9f9f9;
+  margin: 0 -10px 0 -10px;
+  padding: 31px 10px 0px 10px;
+  position: relative;
+}
+#header-wrapper #nav-x div.wrap {
+  max-width: 940px;
+  height: 38px;
+}
+#header-wrapper #nav-x ul.nav-x li {
+  margin-right: 36px !important;
+  margin-top: 5px;
+  margin-bottom: 0px;
+  height: 30px;
+}
+#header-wrapper #nav-x > div.wrap ul.nav-x li.active  {
+  color: #669900;
+  border-bottom: 3px solid #669900;
+}
+#header-wrapper #nav-x > div.wrap ul.nav-x li.active a {
+  color: #669900;
+}
+#header-wrapper #nav-x > div.wrap ul.nav-x a {
+  font-size: 14.5px;
+}
+#header-wrapper .developer-console-btn {
+  float: right;
+  background: #fefefe;
+  border-radius: 4px;
+  padding: 8px 14px;
+  box-shadow: 1px 1px 0px #7a7a7a;
+  font-size: 14px;
+  margin-top: -6px;
+  cursor: pointer;
+  color: #464646;
+  margin-right: 20px;
+}
+/* not currently used */
+#header-wrapper .shadow {
+  width: 1034px;
+  height: 4px;
+  position: absolute;
+  left: 50%;
+  margin-left: -517px;
+  bottom: -4px;
+  background-image: url(../images/header-shadow.png);
+}
+
+#context {
+  clear: both;
+  padding-top: 14px;
+}
+#context .breadcrumb {
+  float: left;
+  margin-bottom: 10px;
+}
+#context .util {
+  float: right;
+  margin-right: 20px;
+}
+
+.breadcrumb {
+  list-style: none;
+  margin: 0;
+  padding: 0;
+  position: relative;
+}
+.breadcrumb li {
+  float: left;
+  padding: 0 20px 0 0;
+  color: #000;
+  white-space: nowrap;
+}
+.breadcrumb li a {
+  color: #000;
+}
+.breadcrumb li:after {
+  content: url(../images/breadcrumb.png);
+  position: relative;
+  top: 1px;
+  left: 10px;
+  width: 5px;
+  height: 10px;
+}
+.breadcrumb li.current {
+  font-weight: 700;
+}
+.breadcrumb li.current:after {
+  display: none;
+}
+
+/* Sticky Nav overrides */
+.sticky-menu {
+  position: fixed;
+  width: 940px;
+  height: 0px;
+  z-index: 51;
+  top: 12px;
+}
+#sticky-header {
+  display: none;
+  padding: 0 10px;
+  position: fixed;
+  background: #f9f9f9;
+  top: 0px;
+  left: 0px;
+  right: 0px;
+  height: 45px;
+  box-shadow: 0px 1px 5px rgba(0, 0, 0, 0.1);
+  border-bottom: 1px solid #a5c43a;
+  z-index: 50;
+}
+#sticky-header.design {
+  border-bottom: 1px solid #33b5e5;
+}
+#sticky-header.develop {
+  border-bottom: 1px solid #F80;
+}
+#sticky-header.distribute {
+  border-bottom: 1px solid #9C0;
+}
+#sticky-header.about {
+  border-bottom: 1px solid #9933CC;
+}
+#sticky-header > div {
+  overflow: hidden;
+  *zoom: 1;
+  width: 940px;
+  margin: 0 auto;
+  clear: both;
+  padding-top: 9px;
+}
+#sticky-header > div .logo {
+  float: left;
+  width: 26px;
+  height: 25px;
+  background: url(../images/dac_logo.png);
+  z-index: 52;
+  position: relative;
+}
+#sticky-header > div .top {
+  float: left;
+  width: 38px;
+  height: 38px;
+  position: relative;
+  background: url(../images/styles/gototop.png);
+  z-index: 52;
+}
+#sticky-header > div .breadcrumb {
+  float: left;
+  padding: 0 0 0 10px;
+  border-left: 1px solid #d2d2d2;
+  line-height: 24px;
+  font-size: 14px;
+  position: relative;
+  top: 0px;
+  z-index: 52;
 }
 
 
-
-
-
-
+}
 
 
 
@@ -4001,7 +4156,6 @@
 }
 
 .logo a {
-  width:123px;
   float:left;
 }
 
@@ -4013,6 +4167,17 @@
   padding-right:10px;
 }
 
+
+#header-wrap .logo.wear-logo {
+  width:220px;
+  margin:0;
+  padding:0;
+  margin-bottom:22px;
+}
+#header-wrap .logo.wear-logo img {
+  padding:0 0 0 10px;
+}
+
 .search {
   height:25px;
   margin-top: -3px;
@@ -4436,11 +4601,11 @@
 }
 
 #nav-x {
-  padding-top: 14px;
+  padding-top: 13px;
 }
 
 #nav-x .wrap {
-  min-height:34px;
+  min-height:32px;
 }
 
 #nav-x .wrap,
@@ -4782,53 +4947,6 @@
 
 
 
-/************ DISTRIBUTE HOMEPAGE ***************/
-
-.marquee {
-  width: 760px;
-}
-.marquee .main-img {
-  float: left;
-  margin-top: 20px;
-  width: 490px;
-}
-.marquee .copy {
-  width: 270px;
-  float: left;
-  margin-top: 30px;
-}
-.distribute-features {
-  margin: 0;
-}
-.distribute-features ul {
-  margin: 0;
-}
-.distribute-features ul li {
-  list-style: none;
-  float: left;
-  border-top: 1px solid #9C0;
-  width: 220px;
-  margin-right: 50px;
-}
-.distribute-features ul li.last {
-  margin-right: 0px;
-}
-
-.distribute-features .distribute-link li a {
-  color:red !important;
-}
-
-.distribute-features .distribute-link li a,
-.distribute-features .distribute-link li a:active {
-  color:#555 !important;
-}
-
-.distribute-features .distribute-link li a:hover,
-.distribute-features .distribute-link li a:hover * {
-  color:#7AA1B0 !important;
-}
-
-
 /************ DEVELOP TOPIC CONTAINERS ************/
 
 .landing-banner,
@@ -5006,3 +5124,1263 @@
 .fullpage #footer {
   margin-top: -40px;
 }
+
+/************ DISTRIBUTE PAGES ******************/
+
+/* Article page header line fix */
+.headerLine {
+  overflow: hidden;
+}
+.headerLine h1 {
+  float: left;
+  padding-right: 20px;
+  margin-bottom: 0px;
+  font-size: 20px;
+  color: #363636;
+}
+.headerLine hr {
+  overflow: hidden;
+  margin: 42px 0 0 0;
+}
+
+.article-detail #body-content {
+  padding-top: 10px;
+}
+
+/* A container for grid sets with uppercase h3 and rule */
+.dynamic-grid h3 {
+  font-size:14px;
+  line-height:21px;
+  color:#555;
+  text-transform:uppercase;
+  border-bottom:1px solid #CCC;
+  padding:8px 0 0 1px;
+  margin-bottom:10px;
+  clear:both;
+}
+
+.top-right-float {
+  float: right;
+}
+
+.clearfloat {
+  float: none;
+  clear: both;
+}
+
+.border-img {
+  border: 1px solid #CCC;
+}
+
+.center-img {
+  margin: auto;
+  text-align: center;
+}
+.center-img img {
+  margin-bottom: 15px;
+}
+
+.figure img, .border-img {
+  margin-bottom: 15px;
+}
+
+/************ RESOURCE CARDS ******************/
+
+/* Resource cards, 12, 13, 16-col */
+
+/* Basic card-styling with shadow */
+.resource-card {
+  border-radius: 1px;
+  box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.14);
+  background: #fefefe;
+}
+
+/* Styling for background image including tinting and section icons in stacks */
+.card-bg {
+  display: block;
+  position: absolute;
+  vertical-align: top;
+  width: 100%;
+  left: 0;
+  top: 0;
+  background-size: cover;
+  background-repeat: no-repeat;
+  background-position: center;
+  background-image: url(../images/resource-card-default-android.jpg);
+}
+.card-bg:after {
+  content: "";
+  display: block;
+  height: 100%;
+  width: 100%;
+  opacity: 1;
+  background: rgba(0, 0, 0, 0.2);
+  -webkit-transition: opacity 0.5s;
+  -moz-transition: opacity 0.5s;
+  -o-transition: opacity 0.5s;
+  transition: opacity 0.5s;
+}
+.card-bg .card-section-icon {
+  position: absolute;
+  top: 50%;
+  width: 100%;
+  margin-top: -35px;
+  text-align: center;
+  padding-top: 65px;
+  z-index: 100;
+}
+.card-bg .card-section-icon .icon {
+  position: absolute;
+  left: 50%;
+  margin-left: -28px;
+  top: 0px;
+  width: 56px;
+  height: 56px;
+  background-repeat: no-repeat;
+  background-position: 50% 50%;
+  background-image: url(../images/stack-icon.png);
+}
+.card-bg .card-section-icon .section {
+  text-transform: uppercase;
+  color: white;
+  font-size: 14px;
+}
+
+.card-info {
+  position: absolute;
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  overflow: hidden;
+  background: #fefefe;
+  padding: 4px 12px 6px 12px;
+}
+.card-info .section {
+  text-transform: uppercase;
+  color: #898989;
+  font-size: 12px;
+  margin-bottom: 1px;
+}
+.card-info .title {
+  color: #363636;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  padding-bottom: 5px;
+  margin-bottom: -2px;
+  font-size: 16px;
+}
+.card-info .description {
+  overflow: hidden;
+}
+.card-info .description .text {
+  color: #464646;
+  font: 13px/15px Roboto Condensed;
+  overflow: hidden;
+  width:100%;
+}
+.card-info .description .util {
+  position: absolute;
+  right: 5px;
+  bottom: 70px; /*-2px;*/
+  opacity: 0;
+  -webkit-transition: opacity 0.5s;
+  -moz-transition: opacity 0.5s;
+  -o-transition: opacity 0.5s;
+  transition: opacity 0.5s;
+}
+.card-info.empty-desc .title {
+  white-space: normal;
+  overflow: visible;
+}
+.card-info.empty-desc .description {
+  display: none;
+}
+/* Truncate card summaries at bounding box and
+ * and apply ellipsis at lower right */
+.ellipsis {
+  overflow: hidden;
+  float:right;
+  line-height: 15px;
+  width:100%;
+}
+.resource-card-6x6 .card-info .description .teddddddxt {
+ float:left;
+  position:relative;
+  margin-left:0;
+}
+.ellipsis:before {
+  content:"";
+  float: left;
+  width: 5px;
+  height:100%;
+}
+.ellipsis > *:first-child.text {
+  float: right;
+  width: 100%  !important;
+  margin-left: -5px;
+}
+.ellipsis:after {
+  content: "\02026";
+  height:17px;
+  padding-bottom:4px;
+
+  box-sizing: content-box;
+  -webkit-box-sizing: content-box;
+  -moz-box-sizing: content-box;
+
+  float: right; position: relative;
+  top: -16px; left: 100%;
+  width: 4em; margin-left: -4em;
+  padding-right: 5px;
+
+  background: -webkit-gradient(linear, left top, right top,
+    from(rgba(255, 255, 255, 0)), to(white), color-stop(65%, white));
+  background: -moz-linear-gradient(to right, rgba(255, 255, 255, 0), white 65%, white);
+  background: -o-linear-gradient(to right, rgba(255, 255, 255, 0), white 65%, white);
+  background: -ms-linear-gradient(to right, rgba(255, 255, 255, 0), white 65%, white);
+  background: linear-gradient(to right, rgba(255, 255, 255, 0), white 65%, white);
+}
+.ellipsis:after {
+  font-style: normal; color: #aaa;
+  font-size:13px;
+  text-align: right;
+}
+
+/* Flow Layout */
+.resource-flow-layout {
+  display: inline-block;
+}
+.resource-flow-layout .resource-card, .resource-flow-layout .resource-card-stack {
+  float: left;
+  position: relative;
+}
+.resource-flow-layout .resource-card-stack > .resource-card {
+  margin-right: 0px !important;
+}
+.resource-flow-layout:after {
+  content: ".";
+  display: block;
+  height: 0;
+  clear: both;
+  visibility: hidden;
+}
+
+.resource-card:hover {
+  cursor: pointer;
+}
+.resource-card:hover .card-bg:after {
+  opacity: 0;
+}
+/* disabled to make way for fade/ellipsis truncation,
+   and the plusone moves up. 
+.resource-card:hover .card-info .description .text {
+  padding-right: 70px;
+} */
+.resource-card:hover .card-info .description .util {
+  opacity: 1;
+}
+
+/* Carousel Layout */
+/* Carousel styles for landing page */
+.resource-carousel-layout {
+  margin: 20px 0 20px 0;
+  position: relative;
+  overflow: hidden;
+}
+.resource-carousel-layout .slideshow-prev, .resource-carousel-layout .slideshow-next {
+  display: none;
+}
+.resource-carousel-layout .pagination {
+  bottom: 0px;
+}
+.resource-carousel-layout .frame li {
+  position: relative;
+}
+.resource-carousel-layout .frame li .card-bg {
+  height: 300px;
+}
+.resource-carousel-layout .frame li .card-info {
+  padding: 7px 15px 0px 15px;
+  top: 300px;
+}
+.resource-carousel-layout .frame li .card-info .section {
+  font-size: 13px;
+  margin-bottom: 7px;
+}
+.resource-carousel-layout .frame li .card-info .title {
+  font-size: 25px;
+  margin-bottom: 2px;
+}
+.resource-carousel-layout .frame li .card-info .description {
+  font-family: 15px/16px Roboto Condensed, sans-serif;
+}
+.resource-carousel-layout .frame li .card-info .description .text {
+  height: 40px;
+}
+.resource-carousel-layout .frame li .card-info .description .util {
+  bottom:97px;
+  right:4px;
+}
+
+/* Stack Layout */
+.resource-stack-layout {
+  display: inline-block;
+}
+.resource-stack-layout .resource-card-stack {
+  float: left;
+  position: relative;
+}
+.resource-stack-layout .resource-card {
+  margin-bottom: 20px;
+  display: block;
+  position: relative;
+}
+.resource-stack-layout .section-card-menu > .card-info .section, .resource-stack-layout .section-card > .card-info .title {
+  /*text-transform: uppercase;*/
+  color: #898989;
+  font-size: 17px;
+  line-height: 24px;
+  margin-bottom: 6px;
+}
+.resource-stack-layout .section-card {
+  height: 284px;
+}
+.resource-stack-layout .section-card > .card-bg {
+  height: 192px;
+}
+.resource-stack-layout .section-card > .card-info {
+  padding: 4px 12px 6px 12px;
+  top: 192px;
+}
+.resource-stack-layout .section-card > .card-info .section {
+  display: none;
+}
+.resource-stack-layout .section-card > .card-info .title {
+  font-size: 17px;
+  border-bottom: 1px solid #959595;
+  padding-bottom: 0px;
+}
+.resource-stack-layout .section-card > .card-info .description {
+  font-size: 13px;
+  line-height: 15px;
+}
+.resource-stack-layout .section-card > .card-info .description .text {
+  height: 30px;
+}
+.resource-stack-layout .related-card {
+  height: 90px;
+}
+.resource-stack-layout .related-card > .card-bg {
+  left: 0;
+  top: 0;
+  width: 90px;
+  height: 100%;
+  position: absolute;
+  display: block;
+}
+.resource-stack-layout .related-card > .card-info {
+  left: 90px;
+  padding: 4px 12px 4px 12px;
+}
+.resource-stack-layout .related-card > .card-info .section {
+  font-size: 12px;
+  margin-bottom: 1px;
+  display: none;
+}
+.resource-stack-layout .related-card > .card-info .title {
+  font-size: 16px;
+  margin-bottom: -2px;
+  white-space: normal;
+  overflow: visible;
+  text-overflow: ellipsis;
+}
+.resource-stack-layout .related-card > .card-info .title:after {
+  content: url(../images/link-out.png);
+  display: block;
+}
+.resource-stack-layout .related-card > .card-info .description {
+  display: none;
+}
+.resource-stack-layout .section-card-menu {
+  /* Flexible height */
+  display: block;
+  height: auto;
+  width: auto;
+}
+.resource-stack-layout .section-card-menu .card-bg {
+  height: 155px;
+  /* Flexible height */
+  position: relative;
+  display: inline-block;
+  vertical-align: top;
+}
+.resource-stack-layout .section-card-menu .card-info {
+  padding: 4px 12px 0px 12px;
+  /* Flexible height */
+  position: relative;
+  left: auto;
+  top: auto;
+  right: auto;
+  bottom: auto;
+}
+.resource-stack-layout .section-card-menu .card-info ul {
+  list-style: none;
+  margin: 0;
+}
+.resource-stack-layout .section-card-menu .card-info ul li {
+  list-style: none;
+  margin: 0;
+  padding: 15px 0;
+  border-top-width: 1px;
+  border-top-style: solid;
+  border-top-color: #959595;
+}
+.resource-stack-layout .section-card-menu .card-info ul li a, .resource-stack-layout .section-card-menu .card-info ul li a:focus, .resource-stack-layout .section-card-menu .card-info ul li a:link, .resource-stack-layout .section-card-menu .card-info ul li a:visited, .resource-stack-layout .section-card-menu .card-info ul li a:active, .resource-stack-layout .section-card-menu .card-info ul li a:hover {
+  color: #363636 !important;
+}
+.resource-stack-layout .section-card-menu .card-info ul li:first-child {
+  border-top: none;
+}
+.resource-stack-layout .section-card-menu .card-info ul li:hover .title:after {
+  opacity: 1;
+  -webkit-transition: opacity 0.5s;
+  -moz-transition: opacity 0.5s;
+  -o-transition: opacity 0.5s;
+  transition: opacity 0.5s;
+}
+.resource-stack-layout .section-card-menu .card-info ul li:hover .description {
+  max-height: 30px;
+  opacity: 1;
+  -webkit-transition: max-height 0.5s, opacity 1s;
+  -moz-transition: max-height 0.5s, opacity 1s;
+  -o-transition: max-height 0.5s, opacity 1s;
+  transition: max-height 0.5s, opacity 1s;
+}
+.resource-stack-layout .section-card-menu .card-info .title {
+  font-size: 16px;
+  margin-bottom: -2px;
+  position: relative;
+}
+.resource-stack-layout .section-card-menu .card-info .title:after {
+  background: url(../images/stack-arrow-right.png);
+  content: '';
+  opacity: 0;
+  -webkit-transition: opacity 0.25s;
+  -moz-transition: opacity 0.25s;
+  -o-transition: opacity 0.25s;
+  transition: opacity 0.25s;
+  position: absolute;
+  right: 0px;
+  top: 3px;
+  width: 10px;
+  height: 15px;
+}
+.resource-stack-layout .section-card-menu .card-info .title.more {
+  text-transform: uppercase;
+  color: #898989;
+  display: inline-block;
+}
+.resource-stack-layout .section-card-menu .card-info .title.more:after {
+  background: url(../images/stack-arrow-right.png);
+  content: '';
+  display: block;
+  position: absolute;
+  right: -20px;
+  top: 3px;
+  width: 10px;
+  height: 15px;
+}
+.resource-stack-layout .section-card-menu .card-info .description {
+  max-height: 0px;
+  opacity: 0;
+  overflow: hidden;
+  font-size: 13px;
+  line-height: 15px;
+  /* Hover off */
+  -webkit-transition: max-height 0.5s, opacity 0.5s;
+  -moz-transition: max-height 0.5s, opacity 0.5s;
+  -o-transition: max-height 0.5s, opacity 0.5s;
+  transition: max-height 0.5s, opacity 0.5s;
+}
+.resource-stack-layout .section-card-menu .card-info .description .text {
+  height: 30px;
+}
+.resource-stack-layout:after {
+  content: ".";
+  display: block;
+  height: 0;
+  clear: both;
+  visibility: hidden;
+}
+
+/* Generate the flow layout styles for a 3-column 16-col span */
+.resource-flow-layout.col-16 {
+  margin: 0 -14px 0 0;
+  width: 954px;
+}
+.resource-flow-layout.col-16 .resource-card, .resource-flow-layout.col-16 .resource-card-stack {
+  margin: 0 14px 20px 0;
+}
+.resource-flow-layout.col-16 .resource-card-row-stack-last {
+  margin-bottom: 0px !important;
+}
+.resource-flow-layout.col-16 .resource-card-col-stack-last {
+  margin-bottom: 0px !important;
+}
+.resource-flow-layout.col-16 .resource-card-3x6 {
+  width: 145px;
+  height: 284px;
+}
+.resource-flow-layout.col-16 .resource-card-3x12 {
+  width: 145px;
+  height: 588px;
+}
+.resource-flow-layout.col-16 .resource-card-3x18 {
+  width: 145px;
+  height: 892px;
+}
+.resource-flow-layout.col-16 .resource-card-6x6 {
+  width: 304px;
+  height: 284px;
+}
+.resource-flow-layout.col-16 .resource-card-6x12 {
+  width: 304px;
+  height: 588px;
+}
+.resource-flow-layout.col-16 .resource-card-6x18 {
+  width: 304px;
+  height: 892px;
+}
+.resource-flow-layout.col-16 .resource-card-9x6 {
+  width: 463px;
+  height: 284px;
+}
+.resource-flow-layout.col-16 .resource-card-9x12 {
+  width: 463px;
+  height: 588px;
+}
+.resource-flow-layout.col-16 .resource-card-9x18 {
+  width: 463px;
+  height: 892px;
+}
+.resource-flow-layout.col-16 .resource-card-12x6 {
+  width: 622px;
+  height: 284px;
+}
+.resource-flow-layout.col-16 .resource-card-12x12 {
+  width: 622px;
+  height: 588px;
+}
+.resource-flow-layout.col-16 .resource-card-12x18 {
+  width: 622px;
+  height: 892px;
+}
+.resource-flow-layout.col-16 .resource-card-15x6 {
+  width: 781px;
+  height: 284px;
+}
+.resource-flow-layout.col-16 .resource-card-15x12 {
+  width: 781px;
+  height: 588px;
+}
+.resource-flow-layout.col-16 .resource-card-15x18 {
+  width: 781px;
+  height: 892px;
+}
+.resource-flow-layout.col-16 .resource-card-18x6 {
+  width: 940px;
+  height: 284px;
+}
+.resource-flow-layout.col-16 .resource-card-18x12 {
+  width: 940px;
+  height: 420px;
+}
+.resource-flow-layout.col-16 .resource-card-18x18 {
+  width: 940px;
+  height: 892px;
+}
+.resource-flow-layout.col-16 .resource-card-3x2 {
+  width: 145px;
+  height: 95px;
+}
+.resource-flow-layout.col-16 .resource-card-3x2x3 {
+  width: 145px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-16 .resource-card-3x3 {
+  width: 145px;
+  height: 142px;
+}
+.resource-flow-layout.col-16 .resource-card-3x3x2 {
+  width: 145px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-16 .resource-card-6x2 {
+  width: 304px;
+  height: 95px;
+}
+.resource-flow-layout.col-16 .resource-card-6x2x3 {
+  width: 304px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-16 .resource-card-6x3 {
+  width: 304px;
+  height: 142px;
+}
+.resource-flow-layout.col-16 .resource-card-6x3x2 {
+  width: 304px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-16 .resource-card-9x2 {
+  width: 463px;
+  height: 95px;
+}
+.resource-flow-layout.col-16 .resource-card-9x2x3 {
+  width: 463px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-16 .resource-card-9x3 {
+  width: 463px;
+  height: 142px;
+}
+.resource-flow-layout.col-16 .resource-card-9x3x2 {
+  width: 463px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-16 .resource-card-12x2 {
+  width: 622px;
+  height: 95px;
+}
+.resource-flow-layout.col-16 .resource-card-12x2x3 {
+  width: 622px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-16 .resource-card-12x3 {
+  width: 622px;
+  height: 142px;
+}
+.resource-flow-layout.col-16 .resource-card-12x3x2 {
+  width: 622px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-16 .resource-card-15x2 {
+  width: 781px;
+  height: 95px;
+}
+.resource-flow-layout.col-16 .resource-card-15x2x3 {
+  width: 781px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-16 .resource-card-15x3 {
+  width: 781px;
+  height: 142px;
+}
+.resource-flow-layout.col-16 .resource-card-15x3x2 {
+  width: 781px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-16 .resource-card-18x2 {
+  width: 940px;
+  height: 95px;
+}
+.resource-flow-layout.col-16 .resource-card-18x2x3 {
+  width: 940px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-16 .resource-card-18x3 {
+  width: 940px;
+  height: 142px;
+}
+.resource-flow-layout.col-16 .resource-card-18x3x2 {
+  width: 940px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+
+/* Generate the flow layout styles for a 3-column 16-col span */
+.resource-flow-layout.col-12 {
+  margin: 0 -14px 0 0;
+  width: 714px;
+}
+
+.resource-flow-layout.col-12 .resource-card, .resource-flow-layout.col-12 .resource-card-stack {
+  margin: 0 14px 20px 0;
+}
+.resource-flow-layout.col-12 .resource-card-row-stack-last {
+  margin-bottom: 0px !important;
+}
+.resource-flow-layout.col-12 .resource-card-col-stack-last {
+  margin-bottom: 0px !important;
+}
+.resource-flow-layout.col-12 .resource-card-3x6 {
+  width: 105px;
+  height: 284px;
+}
+.resource-flow-layout.col-12 .resource-card-3x12 {
+  width: 105px;
+  height: 588px;
+}
+.resource-flow-layout.col-12 .resource-card-3x18 {
+  width: 105px;
+  height: 892px;
+}
+.resource-flow-layout.col-12 .resource-card-6x6 {
+  width: 224px;
+  height: 284px;
+}
+.resource-flow-layout.col-12 .resource-card-6x12 {
+  width: 224px;
+  height: 588px;
+}
+.resource-flow-layout.col-12 .resource-card-6x18 {
+  width: 224px;
+  height: 892px;
+}
+.resource-flow-layout.col-12 .resource-card-9x6 {
+  width: 343px;
+  height: 284px;
+}
+.resource-flow-layout.col-12 .resource-card-9x12 {
+  width: 343px;
+  height: 588px;
+}
+.resource-flow-layout.col-12 .resource-card-9x18 {
+  width: 343px;
+  height: 892px;
+}
+.resource-flow-layout.col-12 .resource-card-12x6 {
+  width: 462px;
+  height: 284px;
+}
+.resource-flow-layout.col-12 .resource-card-12x12 {
+  width: 462px;
+  height: 588px;
+}
+.resource-flow-layout.col-12 .resource-card-12x18 {
+  width: 462px;
+  height: 892px;
+}
+.resource-flow-layout.col-12 .resource-card-15x6 {
+  width: 581px;
+  height: 284px;
+}
+.resource-flow-layout.col-12 .resource-card-15x12 {
+  width: 581px;
+  height: 588px;
+}
+.resource-flow-layout.col-12 .resource-card-15x18 {
+  width: 581px;
+  height: 892px;
+}
+.resource-flow-layout.col-12 .resource-card-18x6 {
+  width: 700px;
+  height: 284px;
+}
+.resource-flow-layout.col-12 .resource-card-18x12 {
+  width: 700px;
+  height: 420px;
+}
+.resource-flow-layout.col-12 .resource-card-18x18 {
+  width: 700px;
+  height: 892px;
+}
+.resource-flow-layout.col-12 .resource-card-3x2 {
+  width: 105px;
+  height: 95px;
+}
+.resource-flow-layout.col-12 .resource-card-3x2x3 {
+  width: 105px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-12 .resource-card-3x3 {
+  width: 105px;
+  height: 142px;
+}
+.resource-flow-layout.col-12 .resource-card-3x3x2 {
+  width: 105px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-12 .resource-card-6x2 {
+  width: 224px;
+  height: 95px;
+}
+.resource-flow-layout.col-12 .resource-card-6x2x3 {
+  width: 224px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-12 .resource-card-6x3 {
+  width: 224px;
+  height: 142px;
+}
+.resource-flow-layout.col-12 .resource-card-6x3x2 {
+  width: 224px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-12 .resource-card-9x2 {
+  width: 343px;
+  height: 95px;
+}
+.resource-flow-layout.col-12 .resource-card-9x2x3 {
+  width: 343px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-12 .resource-card-9x3 {
+  width: 343px;
+  height: 142px;
+}
+.resource-flow-layout.col-12 .resource-card-9x3x2 {
+  width: 343px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-12 .resource-card-12x2 {
+  width: 462px;
+  height: 95px;
+}
+.resource-flow-layout.col-12 .resource-card-12x2x3 {
+  width: 462px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-12 .resource-card-12x3 {
+  width: 462px;
+  height: 142px;
+}
+.resource-flow-layout.col-12 .resource-card-12x3x2 {
+  width: 462px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-12 .resource-card-15x2 {
+  width: 581px;
+  height: 95px;
+}
+.resource-flow-layout.col-12 .resource-card-15x2x3 {
+  width: 581px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-12 .resource-card-15x3 {
+  width: 581px;
+  height: 142px;
+}
+.resource-flow-layout.col-12 .resource-card-15x3x2 {
+  width: 581px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-12 .resource-card-18x2 {
+  width: 700px;
+  height: 95px;
+}
+.resource-flow-layout.col-12 .resource-card-18x2x3 {
+  width: 700px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-12 .resource-card-18x3 {
+  width: 700px;
+  height: 142px;
+}
+.resource-flow-layout.col-12 .resource-card-18x3x2 {
+  width: 700px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+
+/* Generate the flow layout styles for a 3-column 13-col span */
+
+.resource-flow-layout.col-13 {
+  margin: 0 -14px 0 0;
+  width: 774px;
+}
+.resource-flow-layout.col-13 .resource-card, .resource-flow-layout.col-13 .resource-card-stack {
+  margin: 0 14px 20px 0;
+}
+.resource-flow-layout.col-13 .resource-card-row-stack-last {
+  margin-bottom: 0px !important;
+}
+.resource-flow-layout.col-13 .resource-card-col-stack-last {
+  margin-bottom: 0px !important;
+}
+.resource-flow-layout.col-13 .resource-card-3x6 {
+  width: 115px;
+  height: 284px;
+}
+.resource-flow-layout.col-13 .resource-card-3x12 {
+  width: 115px;
+  height: 588px;
+}
+.resource-flow-layout.col-13 .resource-card-3x18 {
+  width: 115px;
+  height: 892px;
+}
+.resource-flow-layout.col-13 .resource-card-6x6 {
+  width: 244px;
+  height: 284px;
+}
+.resource-flow-layout.col-13 .resource-card-6x12 {
+  width: 244px;
+  height: 588px;
+}
+.resource-flow-layout.col-13 .resource-card-6x18 {
+  width: 244px;
+  height: 892px;
+}
+.resource-flow-layout.col-13 .resource-card-9x6 {
+  width: 373px;
+  height: 284px;
+}
+.resource-flow-layout.col-13 .resource-card-9x12 {
+  width: 373px;
+  height: 588px;
+}
+.resource-flow-layout.col-13 .resource-card-9x18 {
+  width: 373px;
+  height: 892px;
+}
+.resource-flow-layout.col-13 .resource-card-12x6 {
+  width: 502px;
+  height: 284px;
+}
+.resource-flow-layout.col-13 .resource-card-12x12 {
+  width: 502px;
+  height: 588px;
+}
+.resource-flow-layout.col-13 .resource-card-12x18 {
+  width: 502px;
+  height: 892px;
+}
+.resource-flow-layout.col-13 .resource-card-15x6 {
+  width: 631px;
+  height: 284px;
+}
+.resource-flow-layout.col-13 .resource-card-15x12 {
+  width: 631px;
+  height: 588px;
+}
+.resource-flow-layout.col-13 .resource-card-15x18 {
+  width: 631px;
+  height: 892px;
+}
+.resource-flow-layout.col-13 .resource-card-18x6 {
+  width: 760px;
+  height: 284px;
+}
+.resource-flow-layout.col-13 .resource-card-18x12 {
+  width: 760px;
+  height: 420px;
+}
+.resource-flow-layout.col-13 .resource-card-18x18 {
+  width: 760px;
+  height: 892px;
+}
+.resource-flow-layout.col-13 .resource-card-3x2 {
+  width: 115px;
+  height: 95px;
+}
+.resource-flow-layout.col-13 .resource-card-3x2x3 {
+  width: 115px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-13 .resource-card-3x3 {
+  width: 115px;
+  height: 142px;
+}
+.resource-flow-layout.col-13 .resource-card-3x3x2 {
+  width: 115px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-13 .resource-card-6x2 {
+  width: 244px;
+  height: 95px;
+}
+.resource-flow-layout.col-13 .resource-card-6x2x3 {
+  width: 244px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-13 .resource-card-6x3 {
+  width: 244px;
+  height: 142px;
+}
+.resource-flow-layout.col-13 .resource-card-6x3x2 {
+  width: 244px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-13 .resource-card-9x2 {
+  width: 373px;
+  height: 95px;
+}
+.resource-flow-layout.col-13 .resource-card-9x2x3 {
+  width: 373px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-13 .resource-card-9x3 {
+  width: 373px;
+  height: 142px;
+}
+.resource-flow-layout.col-13 .resource-card-9x3x2 {
+  width: 373px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-13 .resource-card-12x2 {
+  width: 502px;
+  height: 95px;
+}
+.resource-flow-layout.col-13 .resource-card-12x2x3 {
+  width: 502px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-13 .resource-card-12x3 {
+  width: 502px;
+  height: 142px;
+}
+.resource-flow-layout.col-13 .resource-card-12x3x2 {
+  width: 502px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-13 .resource-card-15x2 {
+  width: 631px;
+  height: 95px;
+}
+.resource-flow-layout.col-13 .resource-card-15x2x3 {
+  width: 631px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-13 .resource-card-15x3 {
+  width: 631px;
+  height: 142px;
+}
+.resource-flow-layout.col-13 .resource-card-15x3x2 {
+  width: 631px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-13 .resource-card-18x2 {
+  width: 760px;
+  height: 95px;
+}
+.resource-flow-layout.col-13 .resource-card-18x2x3 {
+  width: 760px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-13 .resource-card-18x3 {
+  width: 760px;
+  height: 142px;
+}
+.resource-flow-layout.col-13 .resource-card-18x3x2 {
+  width: 760px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+
+/*
+  The following are styles for cards in the flowlayout above, styled by the number of rows they span
+*/
+/* Single row items, might be simpler to just apply a class */
+.resource-card-3x6 > .card-bg, .resource-card-6x6 > .card-bg, .resource-card-9x6 > .card-bg, .resource-card-12x6 > .card-bg, .resource-card-15x6 > .card-bg, .resource-card-18x6 > .card-bg {
+  height: 192px;
+}
+.resource-card-3x6 > .card-info, .resource-card-6x6 > .card-info, .resource-card-9x6 > .card-info, .resource-card-12x6 > .card-info, .resource-card-15x6 > .card-info, .resource-card-18x6 > .card-info {
+  padding: 4px 12px 6px 12px;
+  top: 192px;
+}
+.resource-card-3x6 > .card-info .section, .resource-card-6x6 > .card-info .section, .resource-card-9x6 > .card-info .section, .resource-card-12x6 > .card-info .section, .resource-card-15x6 > .card-info .section, .resource-card-18x6 > .card-info .section {
+  font-size: 12px;
+  margin-bottom: 1px;
+}
+.resource-card-3x6 > .card-info .title, .resource-card-6x6 > .card-info .title, .resource-card-9x6 > .card-info .title, .resource-card-12x6 > .card-info .title, .resource-card-15x6 > .card-info .title, .resource-card-18x6 > .card-info .title {
+  font-size: 16px;
+  margin-bottom: -2px;
+}
+.resource-card-3x6 > .card-info .description, .resource-card-6x6 > .card-info .description, .resource-card-9x6 > .card-info .description, .resource-card-12x6 > .card-info .description, .resource-card-15x6 > .card-info .description, .resource-card-18x6 > .card-info .description {
+  font-size: 13px;
+  line-height: 15px;
+}
+.resource-card-3x6 > .card-info .description .text, .resource-card-6x6 > .card-info .description .text, .resource-card-9x6 > .card-info .description .text, .resource-card-12x6 > .card-info .description .text, .resource-card-15x6 > .card-info .description .text, .resource-card-18x6 > .card-info .description .text {
+  height: 30px;
+}
+
+/* Double row items */
+.resource-card-3x12 > .card-bg, .resource-card-6x12 > .card-bg, .resource-card-9x12 > .card-bg, .resource-card-12x12 > .card-bg, .resource-card-15x12 > .card-bg, .resource-card-18x12 > .card-bg {
+  height: 320px;
+}
+.resource-card-3x12 > .card-info, .resource-card-6x12 > .card-info, .resource-card-9x12 > .card-info, .resource-card-12x12 > .card-info, .resource-card-15x12 > .card-info, .resource-card-18x12 > .card-info {
+  padding: 4px 12px 6px 12px;
+  top: 320px;
+}
+.resource-card-3x12 > .card-info .section, .resource-card-6x12 > .card-info .section, .resource-card-9x12 > .card-info .section, .resource-card-12x12 > .card-info .section, .resource-card-15x12 > .card-info .section, .resource-card-18x12 > .card-info .section {
+  font-size: 12px;
+  margin-bottom: 1px;
+}
+.resource-card-3x12 > .card-info .title, .resource-card-6x12 > .card-info .title, .resource-card-9x12 > .card-info .title, .resource-card-12x12 > .card-info .title, .resource-card-15x12 > .card-info .title, .resource-card-18x12 > .card-info .title {
+  font-size: 16px;
+  margin-bottom: -2px;
+  white-space: normal;
+}
+.resource-card-3x12 > .card-info .description, .resource-card-6x12 > .card-info .description, .resource-card-9x12 > .card-info .description, .resource-card-12x12 > .card-info .description, .resource-card-15x12 > .card-info .description, .resource-card-18x12 > .card-info .description {
+  font-size: 13px;
+  line-height: 15px;
+}
+
+/* 1/3 row items */
+.resource-card-3x2 > .card-bg, .resource-card-6x2 > .card-bg, .resource-card-9x2 > .card-bg, .resource-card-12x2 > .card-bg, .resource-card-15x2 > .card-bg, .resource-card-18x2 > .card-bg {
+  left: 0;
+  top: 0;
+  width: 90px;
+  height: 100%;
+  position: absolute;
+  display: block;
+}
+.resource-card-3x2 > .card-info, .resource-card-6x2 > .card-info, .resource-card-9x2 > .card-info, .resource-card-12x2 > .card-info, .resource-card-15x2 > .card-info, .resource-card-18x2 > .card-info {
+  left: 90px;
+  padding: 4px 12px 4px 12px;
+  height: 80px;
+  overflow: hidden;
+}
+.resource-card-3x2 > .card-info .section, .resource-card-6x2 > .card-info .section, .resource-card-6x3 > .card-info .section, .resource-card-9x2 > .card-info .section, .resource-card-12x2 > .card-info .section, .resource-card-15x2 > .card-info .section, .resource-card-18x2 > .card-info .section {
+  font-size: 12px;
+  margin-bottom: 1px;
+  /* display: none; */
+}
+.resource-card-3x2 > .card-info .title, .resource-card-6x2 > .card-info .title, .resource-card-9x2 > .card-info .title, .resource-card-12x2 > .card-info .title, .resource-card-15x2 > .card-info .title, .resource-card-18x2 > .card-info .title {
+  font-size: 16px;
+  margin-bottom: -2px;
+  white-space: normal;
+  overflow: visible;
+  text-overflow: ellipsis;
+}
+.resource-card-3x2 > .card-info .title:after, .resource-card-6x2 > .card-info .title:after, .resource-card-9x2 > .card-info .title:after, .resource-card-12x2 > .card-info .title:after, .resource-card-15x2 > .card-info .title:after, .resource-card-18x2 > .card-info .title:after {
+  /* content: url(../images/link-out.png); */
+  display: block;
+}
+.resource-card-3x2 > .card-info .description, .resource-card-6x2 > .card-info .description, .resource-card-9x2 > .card-info .description, .resource-card-12x2 > .card-info .description, .resource-card-15x2 > .card-info .description, .resource-card-18x2 > .card-info .description {
+  display: none;
+}
+
+/* 1/2 row items */
+.resource-card-3x3 > .card-bg, .resource-card-6x3 > .card-bg, .resource-card-9x3 > .card-bg, .resource-card-12x3 > .card-bg, .resource-card-15x3 > .card-bg, .resource-card-18x3 > .card-bg {
+  left: 0;
+  top: 0;
+  width: 90px;
+  height: 100%;
+  position: absolute;
+  display: block;
+}
+.resource-card-3x3 > .card-info, .resource-card-6x3 > .card-info, .resource-card-9x3 > .card-info, .resource-card-12x3 > .card-info, .resource-card-15x3 > .card-info, .resource-card-18x3 > .card-info {
+  left: 90px;
+  padding: 4px 12px 0px 12px;
+}
+.resource-card-3x3 > .card-info .section, .resource-card-6x3 > .card-info .section, .resource-card-9x3 > .card-info .section, .resource-card-12x3 > .card-info .section, .resource-card-15x3 > .card-info .section, .resource-card-18x3 > .card-info .section {
+  font-size: 12px;
+  margin-bottom: 1px;
+  display: none;
+}
+.resource-card-3x3 > .card-info .title, .resource-card-6x3 > .card-info .title, .resource-card-9x3 > .card-info .title, .resource-card-12x3 > .card-info .title, .resource-card-15x3 > .card-info .title, .resource-card-18x3 > .card-info .title {
+  font-size: 16px;
+  margin-bottom: -2px;
+  white-space: normal;
+  overflow: visible;
+}
+.resource-card-3x3 > .card-info .description .text, .resource-card-6x3 > .card-info .description .text, .resource-card-9x3 > .card-info .description .text, .resource-card-12x3 > .card-info .description .text, .resource-card-15x3 > .card-info .description .text, .resource-card-18x3 > .card-info .description .text {
+  font-size: 12px;
+  line-height: 15px;
+  padding-right: 0px !important;
+  height: 80px;
+}
+.resource-card-3x3 > .card-info .description .util, .resource-card-6x3 > .card-info .description .util, .resource-card-9x3 > .card-info .description .util, .resource-card-12x3 > .card-info .description .util, .resource-card-15x3 > .card-info .description .util, .resource-card-18x3 > .card-info .description .util {
+  display: none;
+}
+/* placement of plusone */
+.resource-card-6x12 > .card-info .description .util, .resource-card-9x12 > .card-info .description .util, .resource-card-12x12 > .card-info .description .util, .resource-card-15x12 > .card-info .description .util {
+  bottom:2px;
+}
+.resource-card-18x12 > .card-info .description .util {
+  bottom:2px;
+}
+/* Overrides for col-16 6x6 cards linking to local content on landing pages.
+   Suppresses "section" and puts the title above a hairline rule. */
+.landing .card-info .section, .resource-flow-layout.col-16.landing .resource-card-9x6 .card-info .section {
+  display:none;
+}
+.landing  .card-info .title {
+  color: #898989;
+  font-size: 17px;
+  line-height: 24px;
+  margin-bottom: 6px;
+  border-bottom: 1px solid #959595;
+  padding-bottom: 0px;
+}
+.landing .card-info .description {
+  font-size: 13px;
+  line-height: 15px;
+}
+.landing .card-info .description .text {
+height:30px;
+}
+.landing .resource-card-6x6 > .card-info .description .util, .landing .resource-card-9x6 > .card-info .description .util {
+  bottom:2px;
+}
+/*
+  Generate a resource stack layout for a 3 column widget spanning 16 grid cols
+*/
+.resource-stack-layout.col-16 {
+  margin: 0 -14px 0 0;
+  width: 954px;
+}
+.resource-stack-layout.col-16 .resource-card-stack {
+  margin: 0 14px 0 0;
+  width: 304px;
+}
+
+/* Example of card menu tinting */
+.resource-widget[data-section=distribute\/tools] .section-card-menu
+.card-bg:after {
+  background: rgba(126, 55, 148, 0.4) !important;
+}
+.resource-widget[data-section=distribute\/tools] .section-card-menu
+.card-section-icon .icon {
+  background-color: #7e3794 !important;
+}
+.resource-widget[data-section=distribute\/tools] .section-card-menu
+.card-info ul li {
+  border-top-color: #7e3794 !important;
+}
+
+/* tinting for stacks */
+
+div.jd-descr > .resource-widget[data-section=distribute\/tools]
+.section-card-menu .card-info ul li {
+  border-top-color: #7e3794 !important;
+}
\ No newline at end of file
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/css/fullscreen.css b/tools/droiddoc/templates-sdk-dyn/assets/css/fullscreen.css
index 71cf65b..53d9a64 100644
--- a/tools/droiddoc/templates-sdk-dyn/assets/css/fullscreen.css
+++ b/tools/droiddoc/templates-sdk-dyn/assets/css/fullscreen.css
@@ -170,7 +170,7 @@
   max-width: 100%;
 }
 
-#nav-x .wrap,
+#header-wrapper #nav-x div.wrap,
 #searchResults.wrap {
     max-width:100%;
 }
@@ -184,7 +184,18 @@
   left:20px; /* !important ... for IE i think */
 }
 
+#sticky-header {
+  padding: 0 20px;
+}
 
+#sticky-header > div {
+  width: 100%;
+}
+
+.sticky-menu {
+  width:100%;
+  left:-20px;
+}
 
 
 }
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/breadcrumb.png b/tools/droiddoc/templates-sdk-dyn/assets/images/breadcrumb.png
new file mode 100644
index 0000000..407a318
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dyn/assets/images/breadcrumb.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/dac_logo@2x.png b/tools/droiddoc/templates-sdk-dyn/assets/images/dac_logo@2x.png
new file mode 100644
index 0000000..0f2784d
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dyn/assets/images/dac_logo@2x.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/link-out.png b/tools/droiddoc/templates-sdk-dyn/assets/images/link-out.png
new file mode 100644
index 0000000..aa55f9a
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dyn/assets/images/link-out.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-card-default-android.jpg b/tools/droiddoc/templates-sdk-dyn/assets/images/resource-card-default-android.jpg
new file mode 100644
index 0000000..8050744
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dyn/assets/images/resource-card-default-android.jpg
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/stack-arrow-right.png b/tools/droiddoc/templates-sdk-dyn/assets/images/stack-arrow-right.png
new file mode 100644
index 0000000..46d6a50
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dyn/assets/images/stack-arrow-right.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/js/docs.js b/tools/droiddoc/templates-sdk-dyn/assets/js/docs.js
index 6630bf9..e6befe3 100644
--- a/tools/droiddoc/templates-sdk-dyn/assets/js/docs.js
+++ b/tools/droiddoc/templates-sdk-dyn/assets/js/docs.js
@@ -167,10 +167,12 @@
   // highlight Design tab
   if ($("body").hasClass("design")) {
     $("#header li.design a").addClass("selected");
+    $("#sticky-header").addClass("design");
 
   // highlight Develop tab
   } else if ($("body").hasClass("develop") || $("body").hasClass("google")) {
     $("#header li.develop a").addClass("selected");
+    $("#sticky-header").addClass("develop");
     // In Develop docs, also highlight appropriate sub-tab
     var rootDir = pagePathOriginal.substring(1,pagePathOriginal.indexOf('/', 1));
     if (rootDir == "training") {
@@ -195,12 +197,34 @@
   // highlight Distribute tab
   } else if ($("body").hasClass("distribute")) {
     $("#header li.distribute a").addClass("selected");
-  }
+    $("#sticky-header").addClass("distribute");
+
+    var baseFrag = pagePathOriginal.indexOf('/', 1) + 1;
+    var secondFrag = pagePathOriginal.substring(baseFrag, pagePathOriginal.indexOf('/', baseFrag));
+    if (secondFrag == "users") {
+      $("#nav-x li.users a").addClass("selected");
+    } else if (secondFrag == "engage") {
+      $("#nav-x li.engage a").addClass("selected");
+    } else if (secondFrag == "monetize") {
+      $("#nav-x li.monetize a").addClass("selected");
+    } else if (secondFrag == "tools") {
+      $("#nav-x li.disttools a").addClass("selected");
+    } else if (secondFrag == "stories") {
+      $("#nav-x li.stories a").addClass("selected");
+    } else if (secondFrag == "essentials") {
+      $("#nav-x li.essentials a").addClass("selected");
+    } else if (secondFrag == "googleplay") {
+      $("#nav-x li.googleplay a").addClass("selected");
+    }
+  } else if ($("body").hasClass("about")) {
+    $("#sticky-header").addClass("about");
+  } 
 
   // set global variable so we can highlight the sidenav a bit later (such as for google reference)
   // and highlight the sidenav
   mPagePath = pagePath;
   highlightSidenav();
+  buildBreadcrumbs();
 
   // set up prev/next links if they exist
   var $selNavLink = $('#nav').find('a[href="' + pagePath + '"]');
@@ -385,70 +409,6 @@
   });
 
 
-  // Set up fixed navbar
-  var prevScrollLeft = 0; // used to compare current position to previous position of horiz scroll
-  $(window).scroll(function(event) {
-    if ($('#side-nav').length == 0) return;
-    if (event.target.nodeName == "DIV") {
-      // Dump scroll event if the target is a DIV, because that means the event is coming
-      // from a scrollable div and so there's no need to make adjustments to our layout
-      return;
-    }
-    var scrollTop = $(window).scrollTop();
-    var headerHeight = $('#header').outerHeight();
-    var subheaderHeight = $('#nav-x').outerHeight();
-    var searchResultHeight = $('#searchResults').is(":visible") ?
-                             $('#searchResults').outerHeight() : 0;
-    var totalHeaderHeight = headerHeight + subheaderHeight + searchResultHeight;
-    // we set the navbar fixed when the scroll position is beyond the height of the site header...
-    var navBarShouldBeFixed = scrollTop > totalHeaderHeight;
-    // ... except if the document content is shorter than the sidenav height.
-    // (this is necessary to avoid crazy behavior on OSX Lion due to overscroll bouncing)
-    if ($("#doc-col").height() < $("#side-nav").height()) {
-      navBarShouldBeFixed = false;
-    }
-
-    var scrollLeft = $(window).scrollLeft();
-    // When the sidenav is fixed and user scrolls horizontally, reposition the sidenav to match
-    if (navBarIsFixed && (scrollLeft != prevScrollLeft)) {
-      updateSideNavPosition();
-      prevScrollLeft = scrollLeft;
-    }
-
-    // Don't continue if the header is sufficently far away
-    // (to avoid intensive resizing that slows scrolling)
-    if (navBarIsFixed && navBarShouldBeFixed) {
-      return;
-    }
-
-    if (navBarIsFixed != navBarShouldBeFixed) {
-      if (navBarShouldBeFixed) {
-        // make it fixed
-        var width = $('#devdoc-nav').width();
-        $('#devdoc-nav')
-            .addClass('fixed')
-            .css({'width':width+'px'})
-            .prependTo('#body-content');
-        // add neato "back to top" button
-        $('#devdoc-nav a.totop').css({'display':'block','width':$("#nav").innerWidth()+'px'});
-
-        // update the sidenaav position for side scrolling
-        updateSideNavPosition();
-      } else {
-        // make it static again
-        $('#devdoc-nav')
-            .removeClass('fixed')
-            .css({'width':'auto','margin':''})
-            .prependTo('#side-nav');
-        $('#devdoc-nav a.totop').hide();
-      }
-      navBarIsFixed = navBarShouldBeFixed;
-    }
-
-    resizeNav(250); // pass true in order to delay the scrollbar re-initialization for performance
-  });
-
-
   var navBarLeftPos;
   if ($('#devdoc-nav').length) {
     setNavBarLeftPos();
@@ -593,6 +553,28 @@
   });
 }
 
+
+/** Create the list of breadcrumb links in the sticky header */
+function buildBreadcrumbs() {
+  var $breadcrumbUl =  $("#sticky-header ul.breadcrumb");
+  // Add the secondary horizontal nav item, if provided
+  var $selectedSecondNav = $("div#nav-x ul.nav-x a.selected").clone().removeClass("selected");
+  if ($selectedSecondNav.length) {
+    $breadcrumbUl.prepend($("<li>").append($selectedSecondNav))
+  }
+  // Add the primary horizontal nav
+  var $selectedFirstNav = $("div#header-wrap ul.nav-x a.selected").clone().removeClass("selected");
+  // If there's no header nav item, use the logo link and title from alt text
+  if ($selectedFirstNav.length < 1) {
+    $selectedFirstNav = $("<a>")
+        .attr('href', $("div#header .logo a").attr('href'))
+        .text($("div#header .logo img").attr('alt'));
+  }
+  $breadcrumbUl.prepend($("<li>").append($selectedFirstNav));
+}
+
+
+
 /** Highlight the current page in sidenav, expanding children as appropriate */
 function highlightSidenav() {
   // if something is already highlighted, undo it. This is for dynamic navigation (Samples index)
@@ -705,9 +687,8 @@
   // Then figure out based on scroll position whether the header is visible
   var windowHeight = $window.height();
   var scrollTop = $window.scrollTop();
-  var headerHeight = $('#header').outerHeight();
-  var subheaderHeight = $('#nav-x').outerHeight();
-  var headerVisible = (scrollTop < (headerHeight + subheaderHeight));
+  var headerHeight = $('#header-wrapper').outerHeight();
+  var headerVisible = scrollTop < stickyTop;
 
   // get the height of space between nav and top of window.
   // Could be either margin or top position, depending on whether the nav is fixed.
@@ -717,7 +698,7 @@
   // Depending on whether the header is visible, set the side nav's height.
   if (headerVisible) {
     // The sidenav height grows as the header goes off screen
-    navHeight = windowHeight - (headerHeight + subheaderHeight - scrollTop) - topMargin;
+    navHeight = windowHeight - (headerHeight - scrollTop) - topMargin;
   } else {
     // Once header is off screen, the nav height is almost full window height
     navHeight = windowHeight - topMargin;
@@ -905,8 +886,115 @@
 
 
 
+var stickyTop;
+/* Sets the vertical scoll position at which the sticky bar should appear.
+   This method is called to reset the position when search results appear or hide */
+function setStickyTop() {
+  stickyTop = $('#header-wrapper').outerHeight() - $('#sticky-header').outerHeight();
+}
 
 
+/* 
+ * Displays sticky nav bar on pages when dac header scrolls out of view 
+ */
+(function() {
+  $(document).ready(function() {
+
+    setStickyTop();
+    var sticky = false;
+    var hiding = false;
+    var $stickyEl = $('#sticky-header');
+    var $menuEl = $('.menu-container');
+
+    var prevScrollLeft = 0; // used to compare current position to previous position of horiz scroll
+
+    $(window).scroll(function() {
+      // Exit if there's no sidenav
+      if ($('#side-nav').length == 0) return;
+      // Exit if the mouse target is a DIV, because that means the event is coming
+      // from a scrollable div and so there's no need to make adjustments to our layout
+      if (event.target.nodeName == "DIV") {
+        return;
+      }
+
+
+      var top = $(window).scrollTop();
+      // we set the navbar fixed when the scroll position is beyond the height of the site header...
+      var shouldBeSticky = top >= stickyTop;
+      // ... except if the document content is shorter than the sidenav height.
+      // (this is necessary to avoid crazy behavior on OSX Lion due to overscroll bouncing)
+      if ($("#doc-col").height() < $("#side-nav").height()) {
+        shouldBeSticky = false;
+      }
+
+      // Don't continue if the header is sufficently far away
+      // (to avoid intensive resizing that slows scrolling)
+      if (sticky && shouldBeSticky) {
+        return;
+      }
+
+      // Account for horizontal scroll
+      var scrollLeft = $(window).scrollLeft();
+      // When the sidenav is fixed and user scrolls horizontally, reposition the sidenav to match
+      if (navBarIsFixed && (scrollLeft != prevScrollLeft)) {
+        updateSideNavPosition();
+        prevScrollLeft = scrollLeft;
+      }
+
+      // If sticky header visible and position is now near top, hide sticky
+      if (sticky && !shouldBeSticky) {
+        sticky = false;
+        hiding = true;
+        // make the sidenav static again
+        $('#devdoc-nav')
+            .removeClass('fixed')
+            .css({'width':'auto','margin':''})
+            .prependTo('#side-nav');
+        // delay hide the sticky
+        $menuEl.removeClass('sticky-menu');
+        $stickyEl.fadeOut(250);
+        hiding = false;
+
+        // update the sidenaav position for side scrolling
+        updateSideNavPosition();
+      } else if (!sticky && shouldBeSticky) {
+        sticky = true;
+        $stickyEl.fadeIn(10);
+        $menuEl.addClass('sticky-menu');
+
+        // make the sidenav fixed
+        var width = $('#devdoc-nav').width();
+        $('#devdoc-nav')
+            .addClass('fixed')
+            .css({'width':width+'px'})
+            .prependTo('#body-content');
+
+        // update the sidenaav position for side scrolling
+        updateSideNavPosition();
+
+      } else if (hiding && top < 15) {
+        $menuEl.removeClass('sticky-menu');
+        $stickyEl.hide();
+        hiding = false;
+      }
+
+      resizeNav(250); // pass true in order to delay the scrollbar re-initialization for performance
+    });
+
+    // Stack hover states
+    $('.section-card-menu').each(function(index, el) {
+      var height = $(el).height();
+      $(el).css({height:height+'px', position:'relative'});
+      var $cardInfo = $(el).find('.card-info');
+
+      $cardInfo.css({position: 'absolute', bottom:'0px', left:'0px', right:'0px', overflow:'visible'});
+    });
+
+    resizeNav();  // must resize once loading is finished
+  });
+
+})();
+
 
 
 
@@ -1724,6 +1812,7 @@
             $('.suggest-card').hide();
             if ($("#searchResults").is(":hidden") && (search.value != "")) {
               // if results aren't showing (and text not empty), return true to allow search to execute
+              $('body,html').animate({scrollTop:0}, '500', 'swing');
               return true;
             } else {
               // otherwise, results are already showing, so allow ajax to auto refresh the results
@@ -2278,13 +2367,13 @@
   var query = document.getElementById('search_autocomplete').value;
   location.hash = 'q=' + query;
   loadSearchResults();
-  $("#searchResults").slideDown('slow');
+  $("#searchResults").slideDown('slow', setStickyTop);
   return false;
 }
 
 
 function hideResults() {
-  $("#searchResults").slideUp();
+  $("#searchResults").slideUp('fast', setStickyTop);
   $(".search .close").addClass("hide");
   location.hash = '';
 
@@ -2401,7 +2490,7 @@
     return;
   } else {
     // first time loading search results for this page
-    $('#searchResults').slideDown('slow');
+    $('#searchResults').slideDown('slow', setStickyTop);
     $(".search .close").removeClass("hide");
     loadSearchResults();
   }
@@ -2409,19 +2498,22 @@
 
 // when an event on the browser history occurs (back, forward, load) requery hash and do search
 $(window).hashchange( function(){
-  // Exit if the hash isn't a search query or there's an error in the query
+  // If the hash isn't a search query or there's an error in the query,
+  // then adjust the scroll position to account for sticky header, then exit.
   if ((location.hash.indexOf("q=") == -1) || (query == "undefined")) {
     // If the results pane is open, close it.
     if (!$("#searchResults").is(":hidden")) {
       hideResults();
     }
+    // Adjust the scroll position to account for sticky header
+    $(window).scrollTop($(window).scrollTop() - 60);
     return;
   }
 
   // Otherwise, we have a search to do
   var query = decodeURI(getQuery(location.hash));
   searchControl.execute(query);
-  $('#searchResults').slideDown('slow');
+  $('#searchResults').slideDown('slow', setStickyTop);
   $("#search_autocomplete").focus();
   $(".search .close").removeClass("hide");
 
@@ -3233,3 +3325,560 @@
   $("#samples").append($ul);
 
 }
+
+
+
+/* ########################################################## */
+/* ###################  RESOURCE CARDS  ##################### */
+/* ########################################################## */
+
+/** Handle resource queries, collections, and grids (sections). Requires
+    jd_tag_helpers.js and the *_unified_data.js to be loaded. */
+
+(function() {
+  // Prevent the same resource from being loaded more than once per page.
+  var addedPageResources = {};
+
+  $(document).ready(function() {
+    $('.resource-widget').each(function() {
+      initResourceWidget(this);
+    });
+
+    /* Pass the line height to ellipsisfade() to adjust the height of the
+    text container to show the max number of lines possible, without
+    showing lines that are cut off. This works with the css ellipsis
+    classes to fade last text line and apply an ellipsis char. */
+
+    //card text currently uses 15px line height. 
+    var lineHeight = 15;
+    $('.card-info .text').ellipsisfade(lineHeight);
+  });
+
+  /*
+    Three types of resource layouts:
+    Flow - Uses a fixed row-height flow using float left style.
+    Carousel - Single card slideshow all same dimension absolute.
+    Stack - Uses fixed columns and flexible element height.
+  */
+  function initResourceWidget(widget) {
+    var $widget = $(widget);
+    var isFlow = $widget.hasClass('resource-flow-layout'),
+        isCarousel = $widget.hasClass('resource-carousel-layout'),
+        isStack = $widget.hasClass('resource-stack-layout');
+
+    // find size of widget by pulling out its class name
+    var sizeCols = 1;
+    var m = $widget.get(0).className.match(/\bcol-(\d+)\b/);
+    if (m) {
+      sizeCols = parseInt(m[1], 10);
+    }
+
+    var opts = {
+      cardSizes: ($widget.data('cardsizes') || '').split(','),
+      maxResults: parseInt($widget.data('maxresults') || '100', 10),
+      itemsPerPage: $widget.data('itemsperpage'),
+      sortOrder: $widget.data('sortorder'),
+      query: $widget.data('query'),
+      section: $widget.data('section'),
+      sizeCols: sizeCols
+    };
+
+    // run the search for the set of resources to show
+
+    var resources = buildResourceList(opts);
+
+    if (isFlow) {
+      drawResourcesFlowWidget($widget, opts, resources);
+    } else if (isCarousel) {
+      drawResourcesCarouselWidget($widget, opts, resources);
+    } else if (isStack) {
+      var sections = buildSectionList(opts);
+      opts['numStacks'] = $widget.data('numstacks');
+      drawResourcesStackWidget($widget, opts, resources, sections);
+    }
+  }
+
+  /* Initializes a Resource Carousel Widget */
+  function drawResourcesCarouselWidget($widget, opts, resources) {
+    $widget.empty();
+    var plusone = true; //always show plusone on carousel
+
+    $widget.addClass('resource-card slideshow-container')
+      .append($('<a>').addClass('slideshow-prev').text('Prev'))
+      .append($('<a>').addClass('slideshow-next').text('Next'));
+
+    var css = { 'width': $widget.width() + 'px',
+                'height': $widget.height() + 'px' };
+
+    var $ul = $('<ul>');
+
+    for (var i = 0; i < resources.length; ++i) {
+      //keep url clean for matching and offline mode handling
+      var urlPrefix = resources[i].url.indexOf("//") > -1 ? "" : toRoot;
+      var $card = $('<a>')
+        .attr('href', urlPrefix + resources[i].url)
+        .decorateResourceCard(resources[i],plusone);
+
+      $('<li>').css(css)
+          .append($card)
+          .appendTo($ul);
+    }
+
+    $('<div>').addClass('frame')
+      .append($ul)
+      .appendTo($widget);
+
+    $widget.dacSlideshow({
+      auto: true,
+      btnPrev: '.slideshow-prev',
+      btnNext: '.slideshow-next'
+    });
+  };
+
+  /* Initializes a Resource Card Stack Widget (column-based layout) */
+  function drawResourcesStackWidget($widget, opts, resources, sections) {
+    // Don't empty widget, grab all items inside since they will be the first
+    // items stacked, followed by the resource query
+    var plusone = true; //by default show plusone on section cards
+    var cards = $widget.find('.resource-card').detach().toArray();
+    var numStacks = opts.numStacks || 1;
+    var $stacks = [];
+    var urlString;
+
+    for (var i = 0; i < numStacks; ++i) {
+      $stacks[i] = $('<div>').addClass('resource-card-stack')
+          .appendTo($widget);
+    }
+
+    var sectionResources = [];
+
+    // Extract any subsections that are actually resource cards
+    for (var i = 0; i < sections.length; ++i) {
+      if (!sections[i].sections || !sections[i].sections.length) {
+        //keep url clean for matching and offline mode handling
+        urlPrefix = sections[i].url.indexOf("//") > -1 ? "" : toRoot;
+        // Render it as a resource card
+
+        sectionResources.push(
+          $('<a>')
+            .addClass('resource-card section-card')
+            .attr('href', urlPrefix + sections[i].resource.url)
+            .decorateResourceCard(sections[i].resource,plusone)[0]
+        );
+
+      } else {
+        cards.push(
+          $('<div>')
+            .addClass('resource-card section-card-menu')
+            .decorateResourceSection(sections[i],plusone)[0]
+        );
+      }
+    }
+
+    cards = cards.concat(sectionResources);
+
+    for (var i = 0; i < resources.length; ++i) {
+      //keep url clean for matching and offline mode handling
+      urlPrefix = resources[i].url.indexOf("//") > -1 ? "" : toRoot;
+      var $card = $('<a>')
+          .addClass('resource-card related-card')
+          .attr('href', urlPrefix + resources[i].url)
+          .decorateResourceCard(resources[i],plusone);
+
+      cards.push($card[0]);
+    }
+
+    for (var i = 0; i < cards.length; ++i) {
+      // Find the stack with the shortest height, but give preference to
+      // left to right order.
+      var minHeight = $stacks[0].height();
+      var minIndex = 0;
+
+      for (var j = 1; j < numStacks; ++j) {
+        var height = $stacks[j].height();
+        if (height < minHeight - 45) {
+          minHeight = height;
+          minIndex = j;
+        }
+      }
+
+      $stacks[minIndex].append($(cards[i]));
+    }
+
+  };
+
+  /* Initializes a flow widget, see distribute.scss for generating accompanying css */
+  function drawResourcesFlowWidget($widget, opts, resources) {
+    $widget.empty();
+    var cardSizes = opts.cardSizes || ['6x6'];
+    var i = 0, j = 0;
+    var plusone = true; // by default show plusone on resource cards
+
+    while (i < resources.length) {
+      var cardSize = cardSizes[j++ % cardSizes.length];
+      cardSize = cardSize.replace(/^\s+|\s+$/,'');
+      console.log("cardsize is " + cardSize);
+      // Some card sizes do not get a plusone button, such as where space is constrained
+      // or for cards commonly embedded in docs (to improve overall page speed).
+      plusone = !((cardSize == "6x2") || (cardSize == "6x3") ||
+                  (cardSize == "9x2") || (cardSize == "9x3") ||
+                  (cardSize == "12x2") || (cardSize == "12x3"));
+
+      // A stack has a third dimension which is the number of stacked items
+      var isStack = cardSize.match(/(\d+)x(\d+)x(\d+)/);
+      var stackCount = 0;
+      var $stackDiv = null;
+
+      if (isStack) {
+        // Create a stack container which should have the dimensions defined
+        // by the product of the items inside.
+        $stackDiv = $('<div>').addClass('resource-card-stack resource-card-' + isStack[1]
+            + 'x' + isStack[2] * isStack[3]) .appendTo($widget);
+      }
+
+      // Build each stack item or just a single item
+      do {
+        var resource = resources[i];
+        //keep url clean for matching and offline mode handling
+        urlPrefix = resource.url.indexOf("//") > -1 ? "" : toRoot;
+        var $card = $('<a>')
+            .addClass('resource-card resource-card-' + cardSize + ' resource-card-' + resource.type)
+            .attr('href', urlPrefix + resource.url);
+
+        if (isStack) {
+          $card.addClass('resource-card-' + isStack[1] + 'x' + isStack[2]);
+          if (++stackCount == parseInt(isStack[3])) {
+            $card.addClass('resource-card-row-stack-last');
+            stackCount = 0;
+          }
+        } else {
+          stackCount = 0;
+        }
+
+        $card.decorateResourceCard(resource,plusone)
+          .appendTo($stackDiv || $widget);
+
+      } while (++i < resources.length && stackCount > 0);
+    }
+  }
+
+  /* Build a site map of resources using a section as a root. */
+  function buildSectionList(opts) {
+    if (opts.section && SECTION_BY_ID[opts.section]) {
+      return SECTION_BY_ID[opts.section].sections || [];
+    }
+    return [];
+  }
+
+  function buildResourceList(opts) {
+    var maxResults = opts.maxResults || 100;
+
+    var query = opts.query || '';
+    var expressions = parseResourceQuery(query);
+    var addedResourceIndices = {};
+    var results = [];
+
+    for (var i = 0; i < expressions.length; i++) {
+      var clauses = expressions[i];
+
+      // build initial set of resources from first clause
+      var firstClause = clauses[0];
+      var resources = [];
+      switch (firstClause.attr) {
+        case 'type':
+          resources = ALL_RESOURCES_BY_TYPE[firstClause.value];
+          break;
+        case 'lang':
+          resources = ALL_RESOURCES_BY_LANG[firstClause.value];
+          break;
+        case 'tag':
+          resources = ALL_RESOURCES_BY_TAG[firstClause.value];
+          break;
+        case 'collection':
+          var urls = RESOURCE_COLLECTIONS[firstClause.value].resources || [];
+          resources = urls.map(function(url){ return ALL_RESOURCES_BY_URL[url]; });
+          break;
+        case 'section':
+          var urls = SITE_MAP[firstClause.value].sections || [];
+          resources = urls.map(function(url){ return ALL_RESOURCES_BY_URL[url]; });
+          break;
+      }
+      // console.log(firstClause.attr + ':' + firstClause.value);
+      resources = resources || [];
+
+      // use additional clauses to filter corpus
+      if (clauses.length > 1) {
+        var otherClauses = clauses.slice(1);
+        resources = resources.filter(getResourceMatchesClausesFilter(otherClauses));
+      }
+
+      // filter out resources already added
+      if (i > 1) {
+        resources = resources.filter(getResourceNotAlreadyAddedFilter(addedResourceIndices));
+      }
+
+      // add to list of already added indices
+      for (var j = 0; j < resources.length; j++) {
+        // console.log(resources[j].title);
+        addedResourceIndices[resources[j].index] = 1;
+      }
+
+      // concat to final results list
+      results = results.concat(resources);
+    }
+
+    if (opts.sortOrder && results.length) {
+      var attr = opts.sortOrder;
+
+      if (opts.sortOrder == 'random') {
+        var i = results.length, j, temp;
+        while (--i) {
+          j = Math.floor(Math.random() * (i + 1));
+          temp = results[i];
+          results[i] = results[j];
+          results[j] = temp;
+        }
+      } else {
+        var desc = attr.charAt(0) == '-';
+        if (desc) {
+          attr = attr.substring(1);
+        }
+        results = results.sort(function(x,y) {
+          return (desc ? -1 : 1) * (parseInt(x[attr], 10) - parseInt(y[attr], 10));
+        });
+      }
+    }
+
+    results = results.filter(getResourceNotAlreadyAddedFilter(addedPageResources));
+    results = results.slice(0, maxResults);
+
+    for (var j = 0; j < results.length; ++j) {
+      addedPageResources[results[j].index] = 1;
+    }
+
+    return results;
+  }
+
+
+  function getResourceNotAlreadyAddedFilter(addedResourceIndices) {
+    return function(resource) {
+      return !addedResourceIndices[resource.index];
+    };
+  }
+
+
+  function getResourceMatchesClausesFilter(clauses) {
+    return function(resource) {
+      return doesResourceMatchClauses(resource, clauses);
+    };
+  }
+
+
+  function doesResourceMatchClauses(resource, clauses) {
+    for (var i = 0; i < clauses.length; i++) {
+      var map;
+      switch (clauses[i].attr) {
+        case 'type':
+          map = IS_RESOURCE_OF_TYPE[clauses[i].value];
+          break;
+        case 'lang':
+          map = IS_RESOURCE_IN_LANG[clauses[i].value];
+          break;
+        case 'tag':
+          map = IS_RESOURCE_TAGGED[clauses[i].value];
+          break;
+      }
+
+      if (!map || (!!clauses[i].negative ? map[resource.index] : !map[resource.index])) {
+        return clauses[i].negative;
+      }
+    }
+    return true;
+  }
+
+
+  function parseResourceQuery(query) {
+    // Parse query into array of expressions (expression e.g. 'tag:foo + type:video')
+    var expressions = [];
+    var expressionStrs = query.split(',') || [];
+    for (var i = 0; i < expressionStrs.length; i++) {
+      var expr = expressionStrs[i] || '';
+
+      // Break expression into clauses (clause e.g. 'tag:foo')
+      var clauses = [];
+      var clauseStrs = expr.split(/(?=[\+\-])/);
+      for (var j = 0; j < clauseStrs.length; j++) {
+        var clauseStr = clauseStrs[j] || '';
+
+        // Get attribute and value from clause (e.g. attribute='tag', value='foo')
+        var parts = clauseStr.split(':');
+        var clause = {};
+
+        clause.attr = parts[0].replace(/^\s+|\s+$/g,'');
+        if (clause.attr) {
+          if (clause.attr.charAt(0) == '+') {
+            clause.attr = clause.attr.substring(1);
+          } else if (clause.attr.charAt(0) == '-') {
+            clause.negative = true;
+            clause.attr = clause.attr.substring(1);
+          }
+        }
+
+        if (parts.length > 1) {
+          clause.value = parts[1].replace(/^\s+|\s+$/g,'');
+        }
+
+        clauses.push(clause);
+      }
+
+      if (!clauses.length) {
+        continue;
+      }
+
+      expressions.push(clauses);
+    }
+
+    return expressions;
+  }
+})();
+
+(function($) {
+  /* Simple jquery function to create dom for a standard resource card */
+  $.fn.decorateResourceCard = function(resource,plusone) {
+    var section = resource.group || resource.type;
+    var imgUrl;
+    if (resource.image) {
+      //keep url clean for matching and offline mode handling
+      var urlPrefix = resource.image.indexOf("//") > -1 ? "" : toRoot;
+      imgUrl = urlPrefix + resource.image;
+    }
+    //add linkout logic here. check url or type, assign a class, map to css :after
+    $('<div>')
+        .addClass('card-bg')
+        .css('background-image', 'url(' + (imgUrl || toRoot + 'assets/images/resource-card-default-android.jpg') + ')')
+      .appendTo(this);
+    if (!plusone) {
+      $('<div>').addClass('card-info' + (!resource.summary ? ' empty-desc' : ''))
+        .append($('<div>').addClass('section').text(section))
+        .append($('<div>').addClass('title').html(resource.title))
+        .append($('<div>').addClass('description ellipsis')
+            .append($('<div>').addClass('text').html(resource.summary))
+          .append($('<div>').addClass('util')))
+          .appendTo(this);
+    } else {
+      $('<div>').addClass('card-info' + (!resource.summary ? ' empty-desc' : ''))
+        .append($('<div>').addClass('section').text(section))
+        .append($('<div>').addClass('title').html(resource.title))
+        .append($('<div>').addClass('description ellipsis')
+            .append($('<div>').addClass('text').html(resource.summary))
+          .append($('<div>').addClass('util')
+            .append($('<div>').addClass('g-plusone')
+              .attr('data-size', 'small')
+              .attr('data-align', 'right')
+              .attr('data-href', resource.url))))
+            .appendTo(this);
+    }
+
+    return this;
+  };
+
+  /* Simple jquery function to create dom for a resource section card (menu) */
+  $.fn.decorateResourceSection = function(section,plusone) {
+    var resource = section.resource;
+    //keep url clean for matching and offline mode handling
+    var urlPrefix = resource.image.indexOf("//") > -1 ? "" : toRoot;
+    var $base = $('<a>')
+        .addClass('card-bg')
+        .attr('href', resource.url)
+        .append($('<div>').addClass('card-section-icon')
+          .append($('<div>').addClass('icon'))
+          .append($('<div>').addClass('section').html(resource.title)))
+      .appendTo(this);
+
+    var $cardInfo = $('<div>').addClass('card-info').appendTo(this);
+
+    if (section.sections && section.sections.length) {
+      // Recurse the section sub-tree to find a resource image.
+      var stack = [section];
+
+      while (stack.length) {
+        if (stack[0].resource.image) {
+          $base.css('background-image', 'url(' + urlPrefix + stack[0].resource.image + ')');
+          break;
+        }
+
+        if (stack[0].sections) {
+          stack = stack.concat(stack[0].sections);
+        }
+
+        stack.shift();
+      }
+
+      var $ul = $('<ul>')
+        .appendTo($cardInfo);
+
+      var max = section.sections.length > 3 ? 3 : section.sections.length;
+
+      for (var i = 0; i < max; ++i) {
+
+        var subResource = section.sections[i];
+        if (!plusone) {
+          $('<li>')
+            .append($('<a>').attr('href', subResource.url)
+              .append($('<div>').addClass('title').html(subResource.title))
+              .append($('<div>').addClass('description ellipsis')
+                .append($('<div>').addClass('text').html(subResource.summary))
+                .append($('<div>').addClass('util'))))
+          .appendTo($ul);
+        } else {
+          $('<li>')
+            .append($('<a>').attr('href', subResource.url)
+              .append($('<div>').addClass('title').html(subResource.title))
+              .append($('<div>').addClass('description ellipsis')
+                .append($('<div>').addClass('text').html(subResource.summary))
+                .append($('<div>').addClass('util')
+                  .append($('<div>').addClass('g-plusone')
+                    .attr('data-size', 'small')
+                    .attr('data-align', 'right')
+                    .attr('data-href', resource.url)))))
+          .appendTo($ul);
+        }
+      }
+
+      // Add a more row
+      if (max < section.sections.length) {
+        $('<li>')
+          .append($('<a>').attr('href', resource.url)
+            .append($('<div>')
+              .addClass('title')
+              .text('More')))
+        .appendTo($ul);
+      }
+    } else {
+      // No sub-resources, just render description?
+    }
+
+    return this;
+  };
+})(jQuery);
+/* Calculate the vertical area remaining */
+(function($) {
+    $.fn.ellipsisfade= function(lineHeight) {
+        this.each(function() {
+            // get element text
+            var $this = $(this);
+            var remainingHeight = $this.parent().parent().height();
+            $this.parent().siblings().each(function ()
+            {
+              var h = $(this).height();
+              remainingHeight = remainingHeight - h;
+            });
+
+            adjustedRemainingHeight = ((remainingHeight)/lineHeight>>0)*lineHeight
+            $this.parent().css({'height': adjustedRemainingHeight});
+            $this.css({'height': "auto"});
+        });
+
+        return this;
+    };
+}) (jQuery);
diff --git a/tools/droiddoc/templates-sdk-dyn/components/masthead.cs b/tools/droiddoc/templates-sdk-dyn/components/masthead.cs
index 47639bb..d0ff64d 100644
--- a/tools/droiddoc/templates-sdk-dyn/components/masthead.cs
+++ b/tools/droiddoc/templates-sdk-dyn/components/masthead.cs
@@ -1,225 +1,131 @@
 <?cs def:custom_masthead() ?>
+<?cs if:wear ?>
+  <?cs call:wear_masthead() ?>
+<?cs else ?>
 <a name="top"></a>
-<?cs if:!devsite ?><?cs # leave out the global header for devsite; it's in devsite template ?>
-    <!-- Header -->
+<?cs if:!devsite ?><?cs # leave out the global header for devsite; it is in devsite template ?>
+  <!-- Header -->
+  <div id="header-wrapper">
     <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo">
+      <div class="wrap" id="header-wrap">
+        <div class="col-3 logo">
           <a href="<?cs var:toroot ?>index.html">
-            <img src="<?cs var:toroot ?>assets/images/dac_logo.png" width="123" height="25" alt="Android Developers" />
+            <img src="<?cs var:toroot ?>assets/images/dac_logo.png"
+                srcset="<?cs var:toroot ?>assets/images/dac_logo@2x.png 2x"
+                width="123" height="25" alt="Android Developers" />
           </a>
           <div class="btn-quicknav" id="btn-quicknav">
-          	<a href="#" class="arrow-inactive">Quicknav</a>
-			      <a href="#" class="arrow-active">Quicknav</a>
+            <a href="#" class="arrow-inactive">Quicknav</a>
+            <a href="#" class="arrow-active">Quicknav</a>
           </div>
-          </div>
-            <ul class="nav-x col-9">
-                <li class="design">
-                  <a href="<?cs var:toroot ?>design/index.html"
-                  zh-tw-lang="設計"
-                  zh-cn-lang="设计"
-                  ru-lang="Проектирование"
-                  ko-lang="디자인"
-                  ja-lang="設計"
-                  es-lang="Diseñar"               
-                  >Design</a></li>
-                <li class="develop"><a href="<?cs var:toroot ?>develop/index.html"
-                  zh-tw-lang="開發"
-                  zh-cn-lang="开发"
-                  ru-lang="Разработка"
-                  ko-lang="개발"
-                  ja-lang="開発"
-                  es-lang="Desarrollar"               
-                  >Develop</a></li>
-                <li class="distribute last"><a href="<?cs var:toroot ?>distribute/index.html"
-                  zh-tw-lang="發佈"
-                  zh-cn-lang="分发"
-                  ru-lang="Распространение"
-                  ko-lang="배포"
-                  ja-lang="配布"
-                  es-lang="Distribuir"               
-                  >Distribute</a></li>
-            </ul>
-            
-            <!-- New Search -->
-            <div class="menu-container">
-            <div class="moremenu">
-    <div id="more-btn"></div>
-  </div>
-  <div class="morehover" id="moremenu">
-    <div class="top"></div>
-    <div class="mid">
-      <div class="header">Links</div>
-      <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
-        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
-        <li><a href="<?cs var:toroot ?>about/index.html">About Android</a></li>
-      </ul>
-      <div class="header">Android Sites</div>
-      <ul>
-        <li><a href="http://www.android.com">Android.com</a></li>
-        <li class="active"><a>Android Developers</a></li>
-        <li><a href="http://source.android.com">Android Open Source Project</a></li>
-      </ul>
-      
-      <?cs # Include language switcher only in online docs ?>
-      <?cs if:android.whichdoc == "online" ?>
-        <div class="header">Language</div>
-          <div id="language" class="locales">
-            <select name="language" onChange="changeLangPref(this.value, true)">
-                <option value="en">English</option>
-                <option value="es">Español</option>
-                <option value="ja">日本語</option>
-                <option value="ko">한국어</option>
-                <option value="ru">Русский</option>
-                <option value="zh-cn">中文 (中国)</option>
-                <option value="zh-tw">中文 (台灣)</option>
-            </select>
-          </div>
-        <script type="text/javascript">
-          <!--
-          loadLangPref();
-            //-->
-        </script>
-      <?cs /if ?>
-      <?cs # End of lang switcher ?>
-
-
-      <br class="clearfix" />
-    </div>
-    <div class="bottom"></div>
-  </div>
-  <div class="search" id="search-container">
-    <div class="search-inner">
-      <div id="search-btn"></div>
-      <div class="left"></div>
-      <form onsubmit="return submit_search()">
-        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '<?cs var:toroot ?>')" 
-onkeyup="return search_changed(event, false, '<?cs var:toroot ?>')" />
-      </form>
-      <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div>
-
-  <div class="search_filtered_wrapper reference">
-    <div class="suggest-card reference no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div>
-
-  <div class="search_filtered_wrapper docs">
-    <div class="suggest-card dummy no-display">&nbsp;</div>
-    <div class="suggest-card develop no-display">
-      <ul class="search_filtered">
-      </ul>
-      <div class="child-card guides no-display">
-      </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">
-      </ul>
-    </div>
-    <div class="suggest-card distribute no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div>
-
-  </div>
-  <!-- /New Search>
-          
-          
-          <!-- Expanded quicknav -->
-           <div id="quicknav" class="col-9">
-                <ul>
-                    <li class="design">
-                      <ul>
-                        <li><a href="<?cs var:toroot ?>design/index.html">Get Started</a></li>
-                        <li><a href="<?cs var:toroot ?>design/style/index.html">Style</a></li>
-                        <li><a href="<?cs var:toroot ?>design/patterns/index.html">Patterns</a></li>
-                        <li><a href="<?cs var:toroot ?>design/building-blocks/index.html">Building Blocks</a></li>
-                        <li><a href="<?cs var:toroot ?>design/downloads/index.html">Downloads</a></li>
-                        <li><a href="<?cs var:toroot ?>design/videos/index.html">Videos</a></li>
-                      </ul>
-                    </li>
-                    <li class="develop">
-                      <ul>
-                        <li><a href="<?cs var:toroot ?>training/index.html"
-                          zh-tw-lang="訓練課程"
-                          zh-cn-lang="培训"
-                          ru-lang="Курсы"
-                          ko-lang="교육"
-                          ja-lang="トレーニング"
-                          es-lang="Capacitación"               
-                          >Training</a></li>
-                        <li><a href="<?cs var:toroot ?>guide/index.html"
-                          zh-tw-lang="API 指南"
-                          zh-cn-lang="API 指南"
-                          ru-lang="Руководства по API"
-                          ko-lang="API 가이드"
-                          ja-lang="API ガイド"
-                          es-lang="Guías de la API"               
-                          >API Guides</a></li>
-                        <li><a href="<?cs var:toroot ?>reference/packages.html"
-                          zh-tw-lang="參考資源"
-                          zh-cn-lang="参考"
-                          ru-lang="Справочник"
-                          ko-lang="참조문서"
-                          ja-lang="リファレンス"
-                          es-lang="Referencia"               
-                          >Reference</a></li>
-                        <li><a href="<?cs var:toroot ?>tools/index.html"
-                          zh-tw-lang="相關工具"
-                          zh-cn-lang="工具"
-                          ru-lang="Инструменты"
-                          ko-lang="도구"
-                          ja-lang="ツール"
-                          es-lang="Herramientas"               
-                          >Tools</a>
-                          <ul><li><a href="<?cs var:toroot ?>sdk/index.html">Get the SDK</a></li></ul>
-                        </li>
-                        <li><a href="<?cs var:toroot ?>google/index.html">Google Services</a>
-                        </li>
-                        <?cs if:android.hasSamples ?>
-                          <li><a href="<?cs var:toroot ?>samples/index.html">Samples</a>
-                          </li>
-                        <?cs /if ?>
-                      </ul>
-                    </li>
-                    <li class="distribute last">
-                      <ul>
-                        <li><a href="<?cs var:toroot ?>distribute/index.html">Google Play</a></li>
-                        <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/index.html">Publishing</a></li>
-                        <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/index.html">Promoting</a></li>
-                        <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/index.html">App Quality</a></li>
-                        <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/index.html">Spotlight</a></li>
-                        <li><a href="<?cs var:toroot ?>distribute/open.html">Open Distribution</a></li>
-                      </ul>
-                    </li>
-                </ul>
-          </div>
-          <!-- /Expanded quicknav -->
         </div>
-    </div>
-    <!-- /Header -->
-    
-    
-  <div id="searchResults" class="wrap" style="display:none;">
-          <h2 id="searchTitle">Results</h2>
-          <div id="leftSearchControl" class="search-control">Loading...</div>
-  </div>
-    
-    
+        <ul class="nav-x col-9">
+            <li class="design">
+              <a href="<?cs var:toroot ?>design/index.html"
+              zh-tw-lang="設計"
+              zh-cn-lang="设计"
+              ru-lang="Проектирование"
+              ko-lang="디자인"
+              ja-lang="設計"
+              es-lang="Diseñar"
+              >Design</a></li>
+            <li class="develop"><a href="<?cs var:toroot ?>develop/index.html"
+              zh-tw-lang="開發"
+              zh-cn-lang="开发"
+              ru-lang="Разработка"
+              ko-lang="개발"
+              ja-lang="開発"
+              es-lang="Desarrollar"
+              >Develop</a></li>
+            <li class="distribute last"><a href="<?cs var:toroot ?>distribute/<?cs
+              if:android.whichdoc == "offline" ?>googleplay/<?cs /if ?>index.html"
+              zh-tw-lang="發佈"
+              zh-cn-lang="分发"
+              ru-lang="Распространение"
+              ko-lang="배포"
+              ja-lang="配布"
+              es-lang="Distribuir"
+              >Distribute</a></li>
+        </ul>
+
+
+        <?cs # ADD SEARCH AND MENU ?>
+        <?cs call:header_search_widget() ?>
+
+
+        <!-- Expanded quicknav -->
+        <div id="quicknav" class="col-9">
+          <ul>
+            <li class="design">
+              <ul>
+                <li><a href="<?cs var:toroot ?>design/index.html">Get Started</a></li>
+                <li><a href="<?cs var:toroot ?>design/style/index.html">Style</a></li>
+                <li><a href="<?cs var:toroot ?>design/patterns/index.html">Patterns</a></li>
+                <li><a href="<?cs var:toroot ?>design/building-blocks/index.html">Building Blocks</a></li>
+                <li><a href="<?cs var:toroot ?>design/downloads/index.html">Downloads</a></li>
+                <li><a href="<?cs var:toroot ?>design/videos/index.html">Videos</a></li>
+              </ul>
+            </li>
+            <li class="develop">
+              <ul>
+                <li><a href="<?cs var:toroot ?>training/index.html"
+                  zh-tw-lang="訓練課程"
+                  zh-cn-lang="培训"
+                  ru-lang="Курсы"
+                  ko-lang="교육"
+                  ja-lang="トレーニング"
+                  es-lang="Capacitación"
+                  >Training</a></li>
+                <li><a href="<?cs var:toroot ?>guide/index.html"
+                  zh-tw-lang="API 指南"
+                  zh-cn-lang="API 指南"
+                  ru-lang="Руководства по API"
+                  ko-lang="API 가이드"
+                  ja-lang="API ガイド"
+                  es-lang="Guías de la API"
+                  >API Guides</a></li>
+                <li><a href="<?cs var:toroot ?>reference/packages.html"
+                  zh-tw-lang="參考資源"
+                  zh-cn-lang="参考"
+                  ru-lang="Справочник"
+                  ko-lang="참조문서"
+                  ja-lang="リファレンス"
+                  es-lang="Referencia"
+                  >Reference</a></li>
+                <li><a href="<?cs var:toroot ?>tools/index.html"
+                  zh-tw-lang="相關工具"
+                  zh-cn-lang="工具"
+                  ru-lang="Инструменты"
+                  ko-lang="도구"
+                  ja-lang="ツール"
+                  es-lang="Herramientas"
+                  >Tools</a>
+                  <ul><li><a href="<?cs var:toroot ?>sdk/index.html">Get the SDK</a></li></ul>
+                </li>
+                <li><a href="<?cs var:toroot ?>google/index.html">Google Services</a>
+                </li>
+                <?cs if:android.hasSamples ?>
+                  <li><a href="<?cs var:toroot ?>samples/index.html">Samples</a>
+                  </li>
+                <?cs /if ?>
+              </ul>
+            </li>
+            <li class="distribute last">
+              <ul>
+                <li><a href="<?cs var:toroot ?>distribute/googleplay/index.html">Google Play</a></li>
+                <li><a href="<?cs var:toroot ?>distribute/essentials/index.html">Essentials</a></li>
+                <li><a href="<?cs var:toroot ?>distribute/users/index.html">Get Users</a></li>
+                <li><a href="<?cs var:toroot ?>distribute/engage/index.html">Engage &amp; Retain</a></li>
+                <li><a href="<?cs var:toroot ?>distribute/monetize/index.html">Monetize</a></li>
+                <li><a href="<?cs var:toroot ?>distribute/tools/index.html">Tools &amp; Reference</a></li>
+                <li><a href="<?cs var:toroot ?>distribute/stories/index.html">Developer Stories</a></li>
+              </ul>
+            </li>
+          </ul>
+        </div><!-- /Expanded quicknav -->
+      </div><!-- end header-wrap.wrap -->
+    </div><!-- end header -->
+
   <?cs if:training || guide || reference || tools || develop || google || samples ?>
     <!-- Secondary x-nav -->
     <div id="nav-x">
@@ -231,7 +137,7 @@
                   ru-lang="Курсы"
                   ko-lang="교육"
                   ja-lang="トレーニング"
-                  es-lang="Capacitación"               
+                  es-lang="Capacitación"
                   >Training</a></li>
                 <li class="guide"><a href="<?cs var:toroot ?>guide/index.html"
                   zh-tw-lang="API 指南"
@@ -239,7 +145,7 @@
                   ru-lang="Руководства по API"
                   ko-lang="API 가이드"
                   ja-lang="API ガイド"
-                  es-lang="Guías de la API"               
+                  es-lang="Guías de la API"
                   >API Guides</a></li>
                 <li class="reference"><a href="<?cs var:toroot ?>reference/packages.html"
                   zh-tw-lang="參考資源"
@@ -247,7 +153,7 @@
                   ru-lang="Справочник"
                   ko-lang="참조문서"
                   ja-lang="リファレンス"
-                  es-lang="Referencia"               
+                  es-lang="Referencia"
                   >Reference</a></li>
                 <li class="tools"><a href="<?cs var:toroot ?>tools/index.html"
                   zh-tw-lang="相關工具"
@@ -267,13 +173,98 @@
                 <?cs /if ?>
             </ul>
         </div>
-        
     </div>
     <!-- /Sendondary x-nav -->
+
+  <?cs elif:distribute || googleplay || essentials || users || engage || monetize || disttools || stories ?>
+    <!-- Secondary distribute x-nav -->
+    <div id="nav-x">
+        <div class="wrap">
+            <ul class="nav-x distribute">
+                <li class="googleplay"><a href="<?cs var:toroot ?>distribute/googleplay/index.html"
+                  >Google Play</a></li>
+                <li class="essentials"><a href="<?cs var:toroot ?>distribute/essentials/index.html"
+                  >Essentials</a></li>
+                <li class="users"><a href="<?cs var:toroot ?>distribute/users/index.html"
+                  >Get Users</a></li>
+                <li class="engage"><a href="<?cs var:toroot ?>distribute/engage/index.html"
+                  >Engage &amp; Retain</a></li>
+                <li class="monetize"><a href="<?cs var:toroot ?>distribute/monetize/index.html"
+                  >Monetize</a>
+                </li>
+                <li class="disttools"><a href="<?cs var:toroot ?>distribute/tools/index.html"
+                  >Tools</a>
+                </li>
+                <li class="stories"><a href="<?cs var:toroot ?>distribute/stories/index.html"
+                  >Stories</a>
+                </li>
+            </ul>
+            <a href="https://play.google.com/apps/publish/" class="developer-console-btn">Developer Console</a>
+        </div> <!-- /Secondary distribute x-nav -->
+    </div>
   <?cs /if ?>
 
-<?cs /if ?>
-<?cs # end if/else !devsite ?>
+    <div id="searchResults" class="wrap" style="display:none;">
+      <h2 id="searchTitle">Results</h2>
+      <div id="leftSearchControl" class="search-control">Loading...</div>
+    </div>
+  </div> <!--end header-wrapper -->
 
-  <?cs 
+  <div id="sticky-header">
+    <div>
+      <a class="logo" href="#top"></a>
+      <a class="top" href="#top"></a>
+      <ul class="breadcrumb">
+        <?cs # More <li> elements added here with javascript ?>
+        <?cs if:!section.landing ?><li class="current"><?cs var:page.title ?></li><?cs
+        /if ?>
+      </ul>
+    </div>
+  </div>
+
+<?cs /if ?><?cs # end if/else !devsite ?>
+<?cs /if ?><?cs # end if/else wear ?><?cs
+/def ?>
+
+<?cs def:wear_masthead() ?>
+<a name="top"></a>
+
+<!-- Header -->
+<div id="header-wrapper">
+  <div id="header">
+    <div class="wrap" id="header-wrap">
+      <div class="col_3 logo wear-logo">
+        <a href="<?cs var:toroot ?>wear/index.html">
+          <img src="<?cs var:toroot ?>wear/images/android-wear.png" height="16" alt="Android Wear" />
+        </a>
+      </div>
+      <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
+
+      <?cs # ADD SEARCH AND MENU ?>
+      <?cs call:header_search_widget() ?>
+
+    </div><!-- end header-wrap -->
+  </div><!-- /Header -->
+
+
+  <div id="searchResults" class="wrap" style="display:none;">
+          <h2 id="searchTitle">Results</h2>
+          <div id="leftSearchControl" class="search-control">Loading...</div>
+  </div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+  <div>
+    <a class="logo" href="#top"></a>
+    <a class="top" href="#top"></a>
+    <ul class="breadcrumb">
+      <?cs # More <li> elements added here with javascript ?>
+      <?cs if:!section.landing ?><li class="current"><?cs var:page.title ?></li><?cs
+      /if ?>
+    </ul>
+  </div>
+</div>
+
+  <?cs
 /def ?>
diff --git a/tools/droiddoc/templates-sdk-dyn/customizations.cs b/tools/droiddoc/templates-sdk-dyn/customizations.cs
index ed57f1c..27822d5 100644
--- a/tools/droiddoc/templates-sdk-dyn/customizations.cs
+++ b/tools/droiddoc/templates-sdk-dyn/customizations.cs
@@ -7,7 +7,6 @@
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <?cs 
         include:"../../../../frameworks/base/docs/html/sdk/sdk_toc.cs" ?>
@@ -15,33 +14,16 @@
 
       </div>
     </div> <!-- end side-nav -->
-<?cs /def ?>
-<?cs 
-def:resources_tab_nav() ?>
+<?cs /def ?><?cs
+
+def:no_nav() ?>
   <div class="wrap clearfix" id="body-content">
-    <a
-    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
-      <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
+<?cs /def ?><?cs
 
-<?cs 
-        include:"../../../../frameworks/base/docs/html/resources/resources_toc.cs" ?>
-
-
-      </div>
-    </div> <!-- end side-nav -->
-    <script>
-      $(document).ready(function() {
-        scrollIntoView("devdoc-nav");
-        });
-    </script>
-<?cs /def ?>
-<?cs
 def:tools_nav() ?>
   <div class="wrap clearfix" id="body-content">
     <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 <?cs 
         include:"../../../../frameworks/base/docs/html/tools/tools_toc.cs" ?>
         
@@ -59,7 +41,6 @@
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 
 <?cs 
@@ -73,14 +54,110 @@
         scrollIntoView("devdoc-nav");
         });
     </script>
-<?cs /def ?>
-<?cs 
+<?cs /def ?><?cs
+
+def:googleplay_nav() ?>
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+<?cs include:"../../../../frameworks/base/docs/html/distribute/googleplay/googleplay_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?><?cs
+
+def:essentials_nav() ?>
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+<?cs include:"../../../../frameworks/base/docs/html/distribute/essentials/essentials_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?><?cs
+
+def:users_nav() ?>
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+<?cs include:"../../../../frameworks/base/docs/html/distribute/users/users_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?><?cs
+
+def:engage_nav() ?>
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+<?cs include:"../../../../frameworks/base/docs/html/distribute/engage/engage_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?><?cs
+
+def:monetize_nav() ?>
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+<?cs include:"../../../../frameworks/base/docs/html/distribute/monetize/monetize_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?><?cs
+
+def:disttools_nav() ?>
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+<?cs include:"../../../../frameworks/base/docs/html/distribute/tools/disttools_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?><?cs
+
+def:stories_nav() ?>
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+<?cs include:"../../../../frameworks/base/docs/html/distribute/stories/stories_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?><?cs
+
 def:guide_nav() ?>
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
-
 
 <?cs 
         include:"../../../../frameworks/base/docs/html/guide/guide_toc.cs" ?>
@@ -99,7 +176,6 @@
   <div class="wrap clearfix" id="body-content">
     <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 
 <?cs
@@ -119,7 +195,6 @@
   <div class="wrap clearfix" id="body-content">
     <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <?cs
         include:"../../../../frameworks/base/docs/html/distribute/distribute_toc.cs" ?>
@@ -139,7 +214,6 @@
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <?cs
         include:"../../../../frameworks/base/docs/html/samples/samples_toc.cs" ?>
@@ -159,7 +233,6 @@
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <?cs
         include:"../../../../frameworks/base/docs/html/google/google_toc.cs" ?>
@@ -183,7 +256,6 @@
   <div class="wrap clearfix" id="body-content">
     <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <?cs
         include:"../../../../frameworks/base/docs/html/about/about_toc.cs" ?>
@@ -198,6 +270,26 @@
     </script>
 <?cs /def ?>
 
+
+<?cs
+def:wear_nav() ?>
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+
+<?cs
+        include:"../../../../frameworks/base/docs/html/wear/wear_toc.cs" ?>
+
+
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?>
+
 <?cs # The default side navigation for the reference docs ?><?cs 
 def:default_left_nav() ?>
 <?cs if:reference.gcm || reference.gms ?>
@@ -206,8 +298,6 @@
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav">
-
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
       <div id="api-nav-header">
         <div id="api-level-toggle">
           <label for="apiLevelCheckbox" class="disabled"
@@ -308,10 +398,111 @@
     <?cs 
 /def ?>
 
+
+<?cs
+def:header_search_widget() ?>
+<div class="menu-container">
+  <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
+  <div class="morehover" id="moremenu">
+    <div class="top"></div>
+    <div class="mid">
+      <div class="header">Links</div>
+      <ul>
+        <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
+        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
+        <li><a href="<?cs var:toroot ?>about/index.html">About Android</a></li>
+      </ul>
+      <div class="header">Android Sites</div>
+      <ul>
+        <li><a href="http://www.android.com">Android.com</a></li>
+        <li class="active"><a>Android Developers</a></li>
+        <li><a href="http://source.android.com">Android Open Source Project</a></li>
+      </ul>
+
+      <?cs # Include language switcher only in online docs ?>
+      <?cs if:android.whichdoc == "online" ?>
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      <?cs /if ?>
+      <?cs # End of lang switcher ?>
+      <br class="clearfix" />
+    </div><!-- end 'mid' -->
+    <div class="bottom"></div>
+  </div><!-- end 'moremenu' -->
+
+  <div class="search" id="search-container">
+    <div class="search-inner">
+      <div id="search-btn"></div>
+      <div class="left"></div>
+      <form onsubmit="return submit_search()">
+        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
+          onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+          onkeydown="return search_changed(event, true, '<?cs var:toroot ?>')"
+          onkeyup="return search_changed(event, false, '<?cs var:toroot ?>')" />
+      </form>
+      <div class="right"></div>
+      <a class="close hide">close</a>
+      <div class="left"></div>
+      <div class="right"></div>
+    </div><!-- end search-inner -->
+  </div><!-- end search-container -->
+
+  <div class="search_filtered_wrapper reference">
+    <div class="suggest-card reference no-display">
+      <ul class="search_filtered">
+      </ul>
+    </div>
+  </div>
+
+  <div class="search_filtered_wrapper docs">
+    <div class="suggest-card dummy no-display">&nbsp;</div>
+    <div class="suggest-card develop no-display">
+      <ul class="search_filtered">
+      </ul>
+      <div class="child-card guides no-display">
+      </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">
+      </ul>
+    </div>
+    <div class="suggest-card distribute no-display">
+      <ul class="search_filtered">
+      </ul>
+    </div>
+  </div>
+</div><!-- end menu-container (search and menu widget) -->
+<?cs /def ?>
+
+
+
 <?cs 
 def:custom_left_nav() ?><?cs
-  if:fullpage ?><?cs 
-    call:fullpage() ?><?cs 
+  if:fullpage ?><?cs
+    call:fullpage() ?><?cs
+  elif:nonavpage ?><?cs
+    call:no_nav() ?><?cs
   elif:guide ?><?cs 
     call:guide_nav() ?><?cs 
   elif:design ?><?cs
@@ -324,15 +515,31 @@
     call:google_nav() ?><?cs 
   elif:samples ?><?cs
     call:samples_nav() ?><?cs
-  elif:more ?><?cs 
-    call:dist_more_nav() ?><?cs
   elif:distribute ?><?cs 
-    call:distribute_nav() ?><?cs 
-  elif:about ?><?cs 
-    call:about_nav() ?><?cs 
-  else ?><?cs 
-    call:default_left_nav() ?> <?cs 
-  /if ?><?cs 
+    if:googleplay ?><?cs
+      call:googleplay_nav() ?><?cs
+    elif:essentials ?><?cs
+      call:essentials_nav() ?><?cs
+    elif:users ?><?cs
+      call:users_nav() ?><?cs
+    elif:engage ?><?cs
+      call:engage_nav() ?><?cs
+    elif:monetize ?><?cs
+      call:monetize_nav() ?><?cs
+    elif:disttools ?><?cs
+      call:disttools_nav() ?><?cs
+    elif:stories ?><?cs
+      call:stories_nav() ?><?cs
+    /if ?><?cs
+  elif:about ?><?cs
+    call:about_nav() ?><?cs
+  elif:distribute ?><?cs
+    call:distribute_nav() ?><?cs
+  elif:wear ?><?cs
+    call:wear_nav() ?><?cs
+  else ?><?cs
+    call:default_left_nav() ?> <?cs
+  /if ?><?cs
 /def ?>
 
 <?cs # appears at the bottom of every page ?><?cs 
diff --git a/tools/droiddoc/templates-sdk-dyn/docpage.cs b/tools/droiddoc/templates-sdk-dyn/docpage.cs
index ea462c9..7eae405 100644
--- a/tools/droiddoc/templates-sdk-dyn/docpage.cs
+++ b/tools/droiddoc/templates-sdk-dyn/docpage.cs
@@ -2,19 +2,36 @@
 <?cs include:"macros.cs" ?>
 <html<?cs if:devsite ?> devsite<?cs /if ?>>
 <?cs include:"head_tag.cs" ?>
-<body class="gc-documentation <?cs if:(google || reference.gms || reference.gcm) ?>google<?cs /if ?>
-  <?cs if:(guide||develop||training||reference||tools||sdk||samples) ?>develop<?cs if:guide ?> guide<?cs /if ?><?cs if:samples ?> samples<?cs /if ?><?cs
+<body class="gc-documentation 
+
+<?cs
+if:(google || reference.gms || reference.gcm) ?>google<?cs /if ?><?cs
+  if:(guide||develop||training||reference||tools||sdk||samples) ?>develop<?cs
+    if:guide ?> guide<?cs /if ?><?cs
+    if:samples ?> samples<?cs /if ?><?cs
+  elif:(distribute||googleplay||essentials||users||engage||monetize||disttools||stories)
+    ?>distribute<?cs
+    if:googleplay ?> googleplay<?cs /if ?><?cs
+    if:essentials ?> essentials<?cs /if ?><?cs
+    if:users ?> users<?cs /if ?><?cs
+    if:engage ?> engage<?cs /if ?><?cs
+    if:monetize ?> monetize<?cs /if ?><?cs
+    if:disttools ?> disttools<?cs /if ?><?cs
+    if:stories ?> stories<?cs /if ?><?cs
   elif:about ?>about<?cs
   elif:design ?>design<?cs
-  elif:distribute ?>distribute<?cs
-  /if ?><?cs
-  if:page.trainingcourse ?> trainingcourse<?cs /if ?>" itemscope itemtype="http://schema.org/Article">
-<?cs include:"header.cs" ?>
+/if ?><?cs
+if:page.trainingcourse ?> trainingcourse<?cs
+/if ?>" itemscope itemtype="http://schema.org/Article"><?cs
+include:"header.cs" ?>
 
-<div <?cs if:fullpage
-?>class="fullpage"<?cs elif:design||tools||about||sdk||distribute
-?>class="col-13" id="doc-col"<?cs else
-?>class="col-12" id="doc-col"<?cs /if ?> >
+<div <?cs
+  if:fullpage
+    ?>class="fullpage"<?cs
+  elif:(design||tools||about||sdk||googleplay||essentials||users||monetize||disttools) && !nonavpage
+    ?>class="col-13" id="doc-col"<?cs
+  elif:!nonavpage
+    ?>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 ?>
   <?cs if:header.hide ?>
@@ -74,6 +91,7 @@
     <?cs /if ?><?cs # end if training ?>
   </div>
   <?cs /if ?>
+
 <?cs elif:samplesProjectIndex ?>
   <div id="api-info-block">
   <div class="sum-details-links">
@@ -83,7 +101,10 @@
   </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">
@@ -181,8 +202,6 @@
 <?cs include:"footer.cs" ?>
 </div><!-- end doc-content -->
 
-<?cs include:"trailer.cs" ?>
-
 <!-- Start of Tag -->
 <script type="text/javascript">
 var axel = Math.random() + "";
@@ -193,6 +212,15 @@
 <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 -->
+
+
+<?cs include:"trailer.cs" ?>
+  <script src="https://developer.android.com/ytblogger_lists_unified.js" type="text/javascript"></script>
+  <script src="<?cs var:toroot ?>jd_lists_unified.js" type="text/javascript"></script>
+  <script src="<?cs var:toroot ?>jd_extras.js" type="text/javascript"></script>
+  <script src="<?cs var:toroot ?>jd_collections.js" type="text/javascript"></script>
+  <script src="<?cs var:toroot ?>jd_tag_helpers.js" type="text/javascript"></script>
+
 </body>
 </html>
 
diff --git a/tools/droiddoc/templates-sdk-dyn/head_tag.cs b/tools/droiddoc/templates-sdk-dyn/head_tag.cs
index 54de169..732118f 100644
--- a/tools/droiddoc/templates-sdk-dyn/head_tag.cs
+++ b/tools/droiddoc/templates-sdk-dyn/head_tag.cs
@@ -15,13 +15,13 @@
 ?><?cs
   # END if/else devsite ?>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="viewport" content="width=device-width" />
+<meta name="viewport" content="width=<?cs
+  if:page.viewport_width ?><?cs
+    var:page.viewport_width ?><?cs
+  else ?>device-width<?cs /if ?>" />
 <?cs
   if:page.metaDescription ?>
 <meta name="Description" content="<?cs var:page.metaDescription ?>"><?cs
-  /if ?><?cs
-  if:page.customHeadTag ?>
-<?cs var:page.customHeadTag ?><?cs
   /if ?>
 <link rel="shortcut icon" type="image/x-icon" href="<?cs var:toroot ?>favicon.ico" />
 <title><?cs 
@@ -31,10 +31,16 @@
 
 <!-- STYLESHEETS -->
 <link rel="stylesheet"
-href="<?cs if:android.whichdoc != 'online' ?>http:<?cs /if ?>//fonts.googleapis.com/css?family=Roboto:regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="<?cs
+if:android.whichdoc != 'online' ?>http:<?cs
+/if ?>//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="<?cs
+if:android.whichdoc != 'online' ?>http:<?cs
+/if ?>//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
 <link href="<?cs var:toroot ?>assets/css/default.css" rel="stylesheet" type="text/css">
 
-<?cs if:reference && !(reference.gms || reference.gcm) ?>
+<?cs if:reference && !(reference.gms || reference.gcm || wear) ?>
 <!-- FULLSCREEN STYLESHEET -->
 <link href="<?cs var:toroot ?>assets/css/fullscreen.css" rel="stylesheet" class="fullscreen"
 type="text/css">
@@ -47,7 +53,10 @@
   ?><script src="<?cs var:toroot ?>_static/js/android_3p-bundle.js" type="text/javascript"></script><?cs
 else
   ?><script src="<?cs var:toroot ?>assets/js/android_3p-bundle.js" type="text/javascript"></script><?cs
-/if ?>
+/if ?><?cs
+  if:page.customHeadTag ?>
+<?cs var:page.customHeadTag ?><?cs
+  /if ?>
 <script type="text/javascript">
   var toRoot = "<?cs var:toroot ?>";
   var metaTags = [<?cs var:meta.tags ?>];
@@ -66,4 +75,4 @@
     var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
   })();
 </script>
-</head>
\ No newline at end of file
+</head>
diff --git a/tools/droiddoc/templates-sdk-dyn/sample.cs b/tools/droiddoc/templates-sdk-dyn/sample.cs
index 684e284..c6f28f8 100644
--- a/tools/droiddoc/templates-sdk-dyn/sample.cs
+++ b/tools/droiddoc/templates-sdk-dyn/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 -->
diff --git a/tools/droiddoc/templates-sdk-dyn/sdkpage.cs b/tools/droiddoc/templates-sdk-dyn/sdkpage.cs
index d98146a..95f6596 100644
--- a/tools/droiddoc/templates-sdk-dyn/sdkpage.cs
+++ b/tools/droiddoc/templates-sdk-dyn/sdkpage.cs
@@ -11,7 +11,7 @@
 <?cs else ?>
   <?cs include:"head_tag.cs" ?>
 <?cs /if ?>
-<body class="gc-documentation 
+<body class="gc-documentation
   <?cs if:(guide||develop||training||reference||tools||sdk) ?>develop<?cs
   elif:design ?>design<?cs
   elif:distribute ?>distribute<?cs
@@ -107,7 +107,7 @@
     </td>
     <td><?cs var:ndk.win64_bytes ?></td>
     <td><?cs var:ndk.win64_checksum ?></td>
-  </tr> 
+  </tr>
  <!--  <tr>
     <td>
   <a onClick="return onDownload(this)"
@@ -199,12 +199,12 @@
     <td><?cs var:ndk.debug_info_checksum ?></td>
   </tr>
   </table>
-  
+
   <?cs ########  HERE IS THE JD DOC CONTENT ######### ?>
   <?cs call:tag_list(root.descr) ?>
 
 
-  
+
 <script>
   function onDownload(link) {
 
@@ -229,13 +229,13 @@
   function onDownloadNdkForRealz(link) {
     if ($("input#agree").is(':checked')) {
       $("#tos").fadeOut('slow');
-      
+
       $('html, body').animate({
           scrollTop: $("#Installing").offset().top
         }, 800, function() {
           $("#Installing").click();
       });
-     
+
       return true;
     } else {
       $("label#agreeLabel").parent().stop().animate({color: "#258AAF"}, 200,
@@ -254,7 +254,7 @@
 </script>
 
   <?cs else ?>
-<?cs # end if NDK ... 
+<?cs # end if NDK ...
 #
 #
 #
@@ -281,11 +281,11 @@
 <h4><a href='' class="expandable"
   onclick="toggleExpandable(this,'.pax');hideExpandable('.myide,.reqs');return false;"
   >DOWNLOAD FOR OTHER PLATFORMS</a></h4>
-  
-  
+
+
 <div class="pax col-13 online" style="display:none;margin:0;">
 
-  
+
 <p class="table-caption"><strong>ADT Bundle</strong></p>
   <table class="download">
     <tr>
@@ -298,7 +298,7 @@
     <td>Windows 32-bit</td>
     <td>
   <a onClick="return onDownload(this)" id="win-bundle32"
-     href="http://dl.google.com/android/adt/<?cs var:sdk.win32_bundle_download ?>"><?cs var:sdk.win32_bundle_download ?></a>
+     href="http://dl.google.com/android/adt/<?cs var:sdk.version ?>/<?cs var:sdk.win32_bundle_download ?>"><?cs var:sdk.win32_bundle_download ?></a>
     </td>
     <td><?cs var:sdk.win32_bundle_bytes ?> bytes</td>
     <td><?cs var:sdk.win32_bundle_checksum ?></td>
@@ -307,7 +307,7 @@
     <td>Windows 64-bit</td>
     <td>
   <a onClick="return onDownload(this)" id="win-bundle64"
-     href="http://dl.google.com/android/adt/<?cs var:sdk.win64_bundle_download ?>"><?cs var:sdk.win64_bundle_download ?></a>
+     href="http://dl.google.com/android/adt/<?cs var:sdk.version ?>/<?cs var:sdk.win64_bundle_download ?>"><?cs var:sdk.win64_bundle_download ?></a>
     </td>
     <td><?cs var:sdk.win64_bundle_bytes ?> bytes</td>
     <td><?cs var:sdk.win64_bundle_checksum ?></td>
@@ -316,7 +316,7 @@
     <td><nobr>Mac OS X 64-bit</nobr></td>
     <td>
   <a onClick="return onDownload(this)" id="mac-bundle64"
-     href="http://dl.google.com/android/adt/<?cs var:sdk.mac64_bundle_download ?>"><?cs var:sdk.mac64_bundle_download ?></a>
+     href="http://dl.google.com/android/adt/<?cs var:sdk.version ?>/<?cs var:sdk.mac64_bundle_download ?>"><?cs var:sdk.mac64_bundle_download ?></a>
     </td>
     <td><?cs var:sdk.mac64_bundle_bytes ?> bytes</td>
     <td><?cs var:sdk.mac64_bundle_checksum ?></td>
@@ -325,7 +325,7 @@
     <td>Linux 32-bit</td>
     <td>
   <a onClick="return onDownload(this)" id="linux-bundle32"
-     href="http://dl.google.com/android/adt/<?cs var:sdk.linux32_bundle_download ?>"><?cs var:sdk.linux32_bundle_download ?></a>
+     href="http://dl.google.com/android/adt/<?cs var:sdk.version ?>/<?cs var:sdk.linux32_bundle_download ?>"><?cs var:sdk.linux32_bundle_download ?></a>
     </td>
     <td><?cs var:sdk.linux32_bundle_bytes ?> bytes</td>
     <td><?cs var:sdk.linux32_bundle_checksum ?></td>
@@ -334,7 +334,7 @@
     <td>Linux 64-bit</td>
     <td>
   <a onClick="return onDownload(this)" id="linux-bundle64"
-     href="http://dl.google.com/android/adt/<?cs var:sdk.linux64_bundle_download ?>"><?cs var:sdk.linux64_bundle_download ?></a>
+     href="http://dl.google.com/android/adt/<?cs var:sdk.version ?>/<?cs var:sdk.linux64_bundle_download ?>"><?cs var:sdk.linux64_bundle_download ?></a>
     </td>
     <td><?cs var:sdk.linux64_bundle_bytes ?> bytes</td>
     <td><?cs var:sdk.linux64_bundle_checksum ?></td>
@@ -396,10 +396,10 @@
 
 
 </div><!-- end col-13 for lower-half content -->
-  
-  
-  
-  
+
+
+
+
 <script>
   if (location.hash == "#Requirements") {
     $('.reqs').show();
@@ -440,17 +440,17 @@
   } else {
     $('.pax').show();
   }
-  
-  
+
+
   function onDownload(link, button, bundle) {
-  
+
     /* set text for download button */
     if (button) {
       $("#downloadForRealz").html($(link).text());
     } else {
       $("#downloadForRealz").html("Download " + $(link).text());
     }
-    
+
     /* if it's a bundle, show the 32/64-bit picker */
     if (bundle) {
       $("#downloadForRealz").attr('bundle','true');
@@ -482,7 +482,7 @@
   function onAgreeChecked() {
     /* verify that the TOS is agreed and a bit version is chosen */
     if ($("input#agree").is(":checked") && $("#bitpicker input:checked").length) {
-      
+
       /* if downloading the bundle */
       if ($("#downloadForRealz").attr('bundle')) {
         /* construct the name of the link we want based on the bit version */
@@ -490,7 +490,7 @@
         /* set the real url for download */
         $("a#downloadForRealz").attr("href", $(linkId).attr("href"));
       }
-      
+
       /* reveal the download button */
       $("a#downloadForRealz").removeClass('disabled');
     } else {
@@ -536,29 +536,29 @@
       <p>Welcome developers! We are pleased to provide you with a preview SDK for the upcoming
     Android 3.0 release, to give you a head-start on developing applications for it.
     </p>
-    
+
       <p>See the <a
     href="<?cs var:toroot ?>sdk/preview/start.html">Getting Started</a> document for more information
     about how to set up the preview SDK and get started.</p>
     <style type="text/css">
     .non-preview { display:none; }
     </style>
-    
+
     <?cs else ?><?cs # it's normal offline docs ?>
-      
+
       <?cs ########  HERE IS THE JD DOC CONTENT FOR OFFLINE ######### ?>
       <?cs call:tag_list(root.descr) ?>
       <style type="text/css">
         body .offline { display:block; }
         body .online { display:none; }
-      </style>      
+      </style>
       <script>
         $('.reqs').show();
       </script>
     <?cs /if ?>
-    
+
   <?cs /if ?> <?cs # end if/else online ?>
-  
+
 <?cs /if ?> <?cs # end if/else NDK ?>
 
 <?cs /if ?> <?cs # end if/else redirect ?>
diff --git a/tools/droiddoc/templates-sdk/assets/css/default.css b/tools/droiddoc/templates-sdk/assets/css/default.css
index aa30c8a..c650277 100644
--- a/tools/droiddoc/templates-sdk/assets/css/default.css
+++ b/tools/droiddoc/templates-sdk/assets/css/default.css
@@ -98,7 +98,8 @@
 #devdoc-nav.fixed {
   position: fixed;
   margin:0;
-  top: 20px; }
+  top: 65px; /* sticky-header height + 20px gutter */
+}
 
 #devdoc-nav span.small {
   font-size:12px;
@@ -157,12 +158,6 @@
 .layout-content-row {
   display: inline-block;
   margin-bottom: 10px; }
-  .layout-content-row:after {
-    content: ".";
-    display: block;
-    height: 0;
-    clear: both;
-    visibility: hidden; }
   * html .layout-content-row {
     height: 1px; }
 
@@ -429,20 +424,19 @@
 /* content header */
 .content-header {
   height: 30px;
-  margin:20px 0 25px;
-  padding:0 0 10px;}
+  margin:36px 0 23px;  /* same as h1 */
+  padding:0 0 10px;}  /* same as h1 */
 .content-header.just-links {
   margin-bottom:0;
   padding-bottom:0;}
 
 .content-header h1 {
-  color:#000;
   margin:0;
-  border-bottom:0;
   padding:0;
+  width: 700px;
 }
 .content-header > div:first-child {
-  height:55px; /* set fixed height for the header div to ensure the
+  height:1px; /* set fixed height for the header div to ensure the
                   next/prev links align with toc on training classes */
 }
 
@@ -450,7 +444,7 @@
   border-top: 1px solid #ccc;
   margin-top: 10px;
   padding-top:10px;
-  height: 30px; }
+  width:100%; }
 
 .content-footer .col-9 {
   margin-left:0;
@@ -461,20 +455,30 @@
 .content-footer.wrap {
   width:940px;
 }
+.content-footer .plus-container {
+  margin:5px 0 0;
+  text-align:right;
+  float:right;
+}
+
+a.back-link {
+    text-decoration: none;
+    text-transform: uppercase;
+}
 
 .paging-links {
-  position: relative; }
+  position: relative;
+  height:30px; }
   .paging-links a {
     position: absolute; }
   .paging-links a,
   .training-nav-top a {
-    font-size: 14px;
-    line-height: 30px;
     color: #555555;
     text-decoration: none;
     text-transform: uppercase; }
     .paging-links .prev-page-link:before,
-    .training-nav-top .prev-page-link:before {
+    .training-nav-top .prev-page-link:before,
+    a.back-link:before {
       content: '';
       background: transparent url(../images/styles/disclosure_left.png) no-repeat scroll 50% 50%;
       width: 10px;
@@ -488,7 +492,7 @@
     .paging-links .prev-page-link {
       left: -15px; }
     .paging-links .next-page-link {
-      right: 0px; }
+      right: 0; }
     .next-page-link:after,
     .start-class-link:after,
     .start-course-link:after,
@@ -505,6 +509,9 @@
     .next-page-link.inline:after {
       content: none; }
 
+  .content-footer .paging-links .next-page-link {
+    left:0;
+  }
 
   .training-nav-top a {
     display:block;
@@ -543,7 +550,6 @@
 
   .paging-links a.start-class-link {
     width:100%;
-    text-align:right;
   }
 
   /* list of classes on course landing page */
@@ -622,19 +628,6 @@
     display:none !important;
   }
 
-  .content-footer.next-class {
-    display:block;
-    border:0;
-    margin-top:0;
-    padding-top:0;
-  }
-
-  .content-footer.next-class a.next-class-link {
-    display:block;
-    float:right;
-    text-transform:uppercase;
-  }
-
 
 
   /* inner-doc tabs w/ title */
@@ -712,6 +705,7 @@
     color: #33b5e5;
     border-bottom-color: #33b5e5; } }
 
+h1:target,
 h2:target,
 h3:target {
     -webkit-animation-name: glowheader;
@@ -893,7 +887,7 @@
   .framed-nexus4-port-216 img {
     width: 216px;
     height: 360px; }
-    
+
 .framed-nexus5-port-span-5 {
   background: transparent url(../images/styles/device_nexus5_blank_port_span5.png) no-repeat
   scroll top left;
@@ -928,6 +922,47 @@
   height: 384px;
 }
 
+/* wear device frames */
+
+.framed-wear-square {
+  background: transparent url(../images/styles/device_wear_square.png) no-repeat scroll top left;
+  background-size: 302px 302px;
+  height:222px;
+  width:222px;
+  padding:40px;
+  overflow:hidden;
+}
+
+.framed-wear-square-small {
+  background: transparent url(../images/styles/device_wear_square_small.png) no-repeat scroll top left;
+  background-size: 169px 200px;
+  height:147px;
+  width:147px;
+  padding:27px 11px;
+  overflow:hidden;
+}
+
+#jd-content
+.framed-wear-square img {
+  height:222px;
+  width: 222px;
+  padding:0;
+  margin:0;
+}
+
+#jd-content
+.framed-wear-square-small img {
+  height:147px;
+  width: 147px;
+  padding:0;
+  margin:0;
+}
+
+
+
+
+
+
 /* landing page disclosures */
 .landing-page-link {
   text-decoration: none;
@@ -1101,12 +1136,13 @@
 }
 h1 {
     color:#333;
-    font-size: 22px;
-    margin: 20px 0 20px;
+    font-size: 34px;
+    margin: 36px 0 27px;
     padding:0 0 10px;
+    font-weight:300;
 }
 h1, h2 {
-    line-height: 32px;
+    line-height: 30px;
 }
 h1.short {
   margin-right:320px;
@@ -1119,21 +1155,24 @@
 }
 h2 {
     color:#333;
-    font-size: 20px;
-    margin: 20px 0 20px;
+    font-size: 26px;
+    margin: 32px 0 20px;
     padding:0;
+    font-weight:300;
 }
 h3 {
     color:#333;
-    font-size: 18px;
+    font-size: 21px;
+    font-weight:400;
+    margin:21px 0 14px 0;
 }
 h3, h4 {
-    color:#333;
-    line-height: 20px;
-    margin: 10px 0;
+    line-height: 21px;
 }
 h4 {
-  font-size: 16px;
+  font-size: 18px;
+  margin: 12px 0;
+  font-weight:500;
 }
 h5 {
   font-size: 14px;
@@ -1146,7 +1185,7 @@
 }
 hr { /* applied to the bottom of h2 elements */
   height: 1px;
-  margin: 5px 0 20px;
+  margin: 3px 0 12px;
   border: 0;
   background: #ccc;
 }
@@ -1215,6 +1254,13 @@
   color: #33B5E5;
   text-decoration: none;
 }
+a.white {
+  color: #fff;
+  text-decoration:underline;
+}
+a.white:hover, a.white:active {
+  color: #ccc !important;
+}
 strong, b {
   font-weight:bold;
   color: #222;
@@ -1248,6 +1294,7 @@
 tr:first-of-type th:first-of-type:empty {
     visibility: hidden;
 }
+
 /* --------------------------------------------------------------------------
 Footer
 */
@@ -1378,8 +1425,7 @@
   .training-nav-top, .training-nav-bottom,
   #doc-col .content-footer,
   .nav-x, .nav-y,
-  .paging-links,
-  a.totop {
+  .paging-links {
       display: none !important;
   }
 
@@ -1504,7 +1550,8 @@
 Header, Login, Nav-X, Search
 */
 #header {
-  padding: 2.2em 0 0.2em 0;
+  margin: 0;
+  padding: 0;
 }
 #header:before, #header:after {
   content: "";
@@ -1522,6 +1569,9 @@
     color: #333;
     font-size: 16px;
 }
+.about a.selected {
+    color: #9933CC;
+}
 .design a.selected {
     color: #33b5e5;
 }
@@ -1833,6 +1883,11 @@
   margin:0 0 0 20px;
 }
 
+.training-nav-top {
+  position:relative;
+  top:73px;
+}
+
 .training-nav-bottom {
   padding:0 0 20px;
 }
@@ -1841,12 +1896,12 @@
 #qv-wrapper {
   float:right;
   clear:right;
-  margin:0 0 0 20px; /* negative top-margin to counter the content-header bottom margin */
-  padding:0 0 20px;
+  margin:6px 0 0 30px; /* negative top-margin to counter the content-header bottom margin */
+  padding:0 0 30px;
 }
 
 #tb-wrapper {
-  margin:-29px 0 0 20px; /* negative top-margin to counter the content-header bottom margin */
+  margin:51px 0 0 20px; /* negative top-margin to counter the content-header bottom margin */
 }
 
 #tb,
@@ -1930,6 +1985,10 @@
   margin:0 15px 10px 35px;
 }
 
+#tb p {
+  margin:0 15px 10px;
+}
+
 #qv ol {
   list-style:none;
   margin:0 15px 15px;
@@ -1958,28 +2017,12 @@
 
 /* related resources blocks in checklists */
 
-.rel-resources {
-  margin:10px 0px;
-  border:1px solid #ccc;
-  background-color:rgba(0, 0, 0, 0.027451);
-  border:1px solid #ccc;
-  font-size:13px;
-  color:#6f6f6f;
-}
+/* related resources sections that have dynamic content */
 
-.rel-resources ul {
-padding: .5em 1em 0 1em;
-}
 
-.rel-resources a {
-font-weight:500;
-}
 
-.rel-resources h3 {
-  margin:4px 15px 0px 15px;
-  font-size:13px;
-  font-weight:600;
-  text-transform:uppercase;
+h3.rel-resources {
+margin:1.25em auto;
 }
 
 /* --------------------------------------------------------------------------
@@ -2359,6 +2402,13 @@
 #doc-col {
   margin-right:0;
 }
+
+/* Uncomment this for preview release watermark
+#doc-col {
+  background: url('../images/preview.png') repeat;
+}
+*/
+
 #doc-content-container {
   margin-left: 291px
 }
@@ -2760,7 +2810,7 @@
 .caption {
   margin: 0.5em 0 2em 0;
   color: #000;
-  font-size: 11.5px; 
+  font-size: 11.5px;
 }
 
 .nolist, .nolist ul, .nolist ol {
@@ -2884,26 +2934,6 @@
   margin:0 0 10px;
 }
 
-#devdoc-nav a.totop {
-  display:block;
-  top:0;
-  width:inherit;
-  background: transparent url(../images/styles/gototop.png) no-repeat scroll 50% 50%;
-  text-indent:-9999em;
-}
-#devdoc-nav a.totop {
-  position:fixed;
-  display:none;
-}
-#devdoc-nav a.totop:hover {
-  background-color:#33B5E5;
-}
-
-.content-footer a.totop {
-  text-transform:uppercase;
-  line-height:30px;
-}
-
 .expandable {
   height:34px;
   padding-left:20px;
@@ -3013,6 +3043,34 @@
 }
 
 
+/* for IDE instruction toggle (Studio/Eclipse/Other) */
+select.ide {
+  background: transparent;
+  border: 1px solid #bbb;
+  border-left: 0;
+  border-right: 0;
+  margin: 10px 0;
+  padding: 10px 0;
+  color:#666;
+}
+select.ide,
+select.ide option {
+  font-family: inherit;
+  font-size:16px;
+  font-weight:500;
+}
+/* hide all except eclipse by default */
+.select-ide.studio,
+.select-ide.other {
+  display:none;
+}
+/* ... unless eclipse also includes one of the others */
+.select-ide.eclipse.studio,
+.select-ide.eclipse.other {
+  display:block;
+}
+
+
 /* -----------------------------------------------
 good/bad example containers
 */
@@ -3365,28 +3423,37 @@
 }
 
 #jd-header {
-  padding: 0 0 5px;
-  margin: 20px 0 10px;
-  font-size:13px;
+  padding: 0 0 12px;
+  margin: 20px 0 12px;
+  font-size:12px;
+  padding-bottom:12px;
   border-bottom:solid 1px #ccc;
 }
 
 #jd-header h1 {
   margin:0;
-  padding:0;
+  padding:0 0 6px 0;
 }
 
+/* not sure if this is needed in the ref docs, disabling for now
+.jd-descr h2 {
+  margin:16px 0;
+}
+*/
+
 /* page-top-right container for reference pages (holds
 links to summary tables) */
 #api-info-block {
-  font-size:13px;
+  font-size:12px;
   margin:20px 0 0;
   padding:0 10px 6px;
   font-weight:normal;
   float:right;
   text-align:right;
   color:#999;
-  max-width:70%;
+  max-width:80%;
+  font-size: 12px;
+  line-height:14px;
 }
 
 #api-info-block div.api-level {
@@ -3403,7 +3470,8 @@
   border-spacing:0;
   margin:0;
   padding:0;
-  font-size:13px;
+  font-size:12px;
+  line-height:14px;
   background-color:transparent;
 }
 .jd-inheritance-table tr td {
@@ -3968,13 +4036,183 @@
   z-index:100;
 }
 
+
+
+
+
+/************ STICKY NAV BAR ******************/
+
+#header-wrapper {
+  background: #f9f9f9;
+  margin: 0 -10px 0 -10px;
+  padding: 31px 10px 0px 10px;
+  position: relative;
+}
+#header-wrapper #nav-x div.wrap {
+  max-width: 940px;
+  height: 38px;
+}
+#header-wrapper #nav-x ul.nav-x li {
+  margin-right: 36px !important;
+  margin-top: 5px;
+  margin-bottom: 0px;
+  height: 30px;
+}
+#header-wrapper #nav-x > div.wrap ul.nav-x li.active  {
+  color: #669900;
+  border-bottom: 3px solid #669900;
+}
+#header-wrapper #nav-x > div.wrap ul.nav-x li.active a {
+  color: #669900;
+}
+#header-wrapper #nav-x > div.wrap ul.nav-x a {
+  font-size: 14.5px;
+}
+#header-wrapper .developer-console-btn {
+  float: right;
+  background: #fefefe;
+  border-radius: 4px;
+  padding: 8px 14px;
+  box-shadow: 1px 1px 0px #7a7a7a;
+  font-size: 14px;
+  margin-top: -6px;
+  cursor: pointer;
+  color: #464646;
+  margin-right: 20px;
+}
+/* not currently used */
+#header-wrapper .shadow {
+  width: 1034px;
+  height: 4px;
+  position: absolute;
+  left: 50%;
+  margin-left: -517px;
+  bottom: -4px;
+  background-image: url(../images/header-shadow.png);
+}
+
+#context {
+  clear: both;
+  padding-top: 14px;
+}
+#context .breadcrumb {
+  float: left;
+  margin-bottom: 10px;
+}
+#context .util {
+  float: right;
+  margin-right: 20px;
+}
+
+.breadcrumb {
+  list-style: none;
+  margin: 0;
+  padding: 0;
+  position: relative;
+}
+.breadcrumb li {
+  float: left;
+  padding: 0 20px 0 0;
+  color: #000;
+  white-space: nowrap;
+}
+.breadcrumb li a {
+  color: #000;
+}
+.breadcrumb li:after {
+  content: url(../images/breadcrumb.png);
+  position: relative;
+  top: 1px;
+  left: 10px;
+  width: 5px;
+  height: 10px;
+}
+.breadcrumb li.current {
+  font-weight: 700;
+}
+.breadcrumb li.current:after {
+  display: none;
+}
+
+/* Sticky Nav overrides */
+.sticky-menu {
+  position: fixed;
+  width: 940px;
+  height: 0px;
+  z-index: 51;
+  top: 12px;
+}
+#sticky-header {
+  display: none;
+  padding: 0 10px;
+  position: fixed;
+  background: #f9f9f9;
+  top: 0px;
+  left: 0px;
+  right: 0px;
+  height: 45px;
+  box-shadow: 0px 1px 5px rgba(0, 0, 0, 0.1);
+  border-bottom: 1px solid #a5c43a;
+  z-index: 50;
+}
+#sticky-header.design {
+  border-bottom: 1px solid #33b5e5;
+}
+#sticky-header.develop {
+  border-bottom: 1px solid #F80;
+}
+#sticky-header.distribute {
+  border-bottom: 1px solid #9C0;
+}
+#sticky-header.about {
+  border-bottom: 1px solid #9933CC;
+}
+#sticky-header > div {
+  overflow: hidden;
+  *zoom: 1;
+  width: 940px;
+  margin: 0 auto;
+  clear: both;
+  padding-top: 9px;
+}
+#sticky-header > div .logo {
+  float: left;
+  width: 26px;
+  height: 25px;
+  background: url(../images/dac_logo.png);
+  background-image: -webkit-image-set(url(../images/dac_logo.png) 1x, url(../images/dac_logo@2x.png) 2x);
+  z-index: 52;
+  position: relative;
+}
+#sticky-header > div .top {
+  float: left;
+  width: 38px;
+  height: 38px;
+  position: relative;
+  background: url(../images/styles/gototop.png);
+  z-index: 52;
+}
+#sticky-header > div .breadcrumb {
+  float: left;
+  padding: 0 0 0 10px;
+  border-left: 1px solid #d2d2d2;
+  line-height: 24px;
+  font-size: 14px;
+  position: relative;
+  top: 0px;
+  z-index: 52;
+}
+
+/* offset the <a name=""> tags in reference to account for sticky nav */
+body.reference a[name] {
+  visibility: hidden;
+  display: block;
+  position: relative;
+  top: -56px;
 }
 
 
-
-
-
-
+}
 
 
 
@@ -4014,7 +4252,6 @@
 }
 
 .logo a {
-  width:123px;
   float:left;
 }
 
@@ -4027,11 +4264,13 @@
 }
 
 
-#header .logo-wear {
+#header-wrap .logo.landing-logo {
   width:220px;
   margin:0;
+  padding:0;
+  margin-bottom:22px;
 }
-#header .logo-wear img {
+#header-wrap .logo.landing-logo img {
   padding:0 0 0 10px;
 }
 
@@ -4103,7 +4342,7 @@
 #quicknav {
  float:none;
  clear:both;
- margin-left:180px;
+ margin-left:0;
  margin-top:-30px;
  display:none;
  overflow:hidden;
@@ -4118,6 +4357,10 @@
   padding:0;
 }
 
+#quicknav ul li.about {
+  border-top:1px solid #9933CC;
+}
+
 #quicknav ul li.design {
   border-top:1px solid #33b5e5;
 }
@@ -4447,7 +4690,9 @@
 }
 
 
-
+#landing h1 {
+  margin:17px 0 20px 0 !important;
+}
 
 a.download-sdk {
     float:right;
@@ -4458,11 +4703,11 @@
 }
 
 #nav-x {
-  padding-top: 14px;
+  padding-top: 13px;
 }
 
 #nav-x .wrap {
-  min-height:34px;
+  min-height:32px;
 }
 
 #nav-x .wrap,
@@ -4618,14 +4863,14 @@
 
 /* Slideshow */
 .slideshow-develop {
-  height: 300px;
+  height: 316px;
   width: 940px;
   position: relative;
   overflow:hidden;
 }
 .slideshow-develop .frame {
   width: 940px;
-  height: 300px;
+  height: 316px;
 }
 .slideshow-develop img.play {
   max-width:350px;
@@ -4657,6 +4902,7 @@
   padding:0;
   margin-bottom:10px;
   border:none;
+  font-size:24px;
 }
 .slideshow-develop .item {
   height: 300px;
@@ -4804,53 +5050,6 @@
 
 
 
-/************ DISTRIBUTE HOMEPAGE ***************/
-
-.marquee {
-  width: 760px;
-}
-.marquee .main-img {
-  float: left;
-  margin-top: 20px;
-  width: 490px;
-}
-.marquee .copy {
-  width: 270px;
-  float: left;
-  margin-top: 30px;
-}
-.distribute-features {
-  margin: 0;
-}
-.distribute-features ul {
-  margin: 0;
-}
-.distribute-features ul li {
-  list-style: none;
-  float: left;
-  border-top: 1px solid #9C0;
-  width: 220px;
-  margin-right: 50px;
-}
-.distribute-features ul li.last {
-  margin-right: 0px;
-}
-
-.distribute-features .distribute-link li a {
-  color:red !important;
-}
-
-.distribute-features .distribute-link li a,
-.distribute-features .distribute-link li a:active {
-  color:#555 !important;
-}
-
-.distribute-features .distribute-link li a:hover,
-.distribute-features .distribute-link li a:hover * {
-  color:#7AA1B0 !important;
-}
-
-
 /************ DEVELOP TOPIC CONTAINERS ************/
 
 .landing-banner,
@@ -4876,7 +5075,8 @@
   margin-bottom:0;
 }
 .landing-banner h1 {
-  margin-top:0;
+  margin-top:16px;
+  padding-bottom:24px;
 }
 .landing-docs,
 .landing-banner {
@@ -5028,3 +5228,2119 @@
 .fullpage #footer {
   margin-top: -40px;
 }
+
+/************ DISTRIBUTE PAGES ******************/
+
+.article-detail #body-content {
+  padding-top: 10px;
+}
+
+/* A container for grid sets with uppercase h3 and rule */
+.dynamic-grid h3 {
+  font-size:14px;
+  line-height:21px;
+  color:#555;
+  text-transform:uppercase;
+  border-bottom:1px solid #CCC;
+  padding:8px 0 0 1px;
+  margin-bottom:14px;
+  clear:both;
+}
+
+.top-right-float {
+  float: right;
+}
+
+.clearfloat {
+  float: none;
+  clear: both;
+}
+
+.border-img {
+  border: 1px solid #CCC;
+}
+
+.center-img {
+  margin: auto;
+  text-align: center;
+}
+.center-img img {
+  margin-bottom: 15px;
+}
+
+.figure img, .border-img {
+  margin-bottom: 15px;
+}
+
+/************ RESOURCE CARDS ******************/
+
+/* Resource cards, 12, 13, 16-col */
+
+/* Basic card-styling with shadow */
+.resource-card {
+  border-radius: 1px;
+  box-shadow: 1px 2px 5px rgba(0, 0, 0, 0.12);
+  background: #fefefe;
+}
+
+/* Styling for background image including tinting and section icons in stacks */
+.card-bg {
+  display: block;
+  position: absolute;
+  vertical-align: top;
+  width: 100%;
+  left: 0;
+  top: 0;
+  background-size: cover;
+  background-repeat: no-repeat;
+  background-position: center;
+  background-image: url(../images/resource-card-default-android.jpg);
+}
+.card-bg:after {
+  content: "";
+  display: block;
+  height: 100%;
+  width: 100%;
+  opacity: 1;
+  background: rgba(0, 0, 0, 0.2);
+  -webkit-transition: opacity 0.5s;
+  -moz-transition: opacity 0.5s;
+  -o-transition: opacity 0.5s;
+  transition: opacity 0.5s;
+}
+.static .card-bg:after {
+  display:none;
+}
+.card-bg .card-section-icon {
+  position: absolute;
+  top: 50%;
+  width: 100%;
+  margin-top: -35px;
+  text-align: center;
+  padding-top: 65px;
+  z-index: 100;
+}
+.card-bg .card-section-icon .icon {
+  position: absolute;
+  left: 50%;
+  margin-left: -28px;
+  top: 0px;
+  width: 56px;
+  height: 56px;
+  background-repeat: no-repeat;
+  background-position: 50% 50%;
+  background-image: url(../images/stack-icon.png);
+}
+.card-bg .card-section-icon .section {
+  text-transform: uppercase;
+  color: white;
+  font-size: 14px;
+}
+
+.card-info {
+  position: absolute;
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  overflow: hidden;
+  background: #fefefe;
+  padding: 4px 12px 6px 12px;
+}
+.card-info .section {
+  text-transform: uppercase;
+  color: #898989;
+  font-size: 12px;
+  margin-bottom: 1px;
+}
+.card-info .title {
+  color: #363636;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  padding-bottom: 5px;
+  margin-bottom: -2px;
+  font-size: 16px;
+}
+.card-info .description {
+  overflow: hidden;
+}
+.card-info .description .text {
+  color: #464646;
+  font: 13px/15px Roboto Condensed;
+  overflow: hidden;
+  width:100%;
+}
+.card-info .description .util {
+  position: absolute;
+  right: 5px;
+  bottom: 70px; /*-2px;*/
+  opacity: 0;
+  -webkit-transition: opacity 0.5s;
+  -moz-transition: opacity 0.5s;
+  -o-transition: opacity 0.5s;
+  transition: opacity 0.5s;
+}
+.card-info.empty-desc .title {
+  white-space: normal;
+  overflow: visible;
+}
+.card-info.empty-desc .description {
+  display: none;
+}
+/* Truncate card summaries at bounding box and
+ * and apply ellipsis at lower right */
+.ellipsis {
+  overflow: hidden;
+  float:right;
+  line-height: 15px;
+  width:100%;
+}
+.resource-card-6x6 .card-info .description .teddddddxt {
+ float:left;
+  position:relative;
+  margin-left:0;
+}
+.ellipsis:before {
+  content:"";
+  float: left;
+  width: 5px;
+  height:100%;
+}
+.ellipsis > *:first-child.text {
+  float: right;
+  width: 100%  !important;
+  margin-left: -5px;
+}
+.ellipsis:after {
+  content: "\02026";
+  height:17px;
+  padding-bottom:4px;
+
+  box-sizing: content-box;
+  -webkit-box-sizing: content-box;
+  -moz-box-sizing: content-box;
+
+  float: right; position: relative;
+  top: -16px; left: 100%;
+  width: 4em; margin-left: -4em;
+  padding-right: 5px;
+
+  background: -webkit-gradient(linear, left top, right top,
+    from(rgba(255, 255, 255, 0)), to(white), color-stop(65%, white));
+  background: -moz-linear-gradient(to right, rgba(255, 255, 255, 0), white 65%, white);
+  background: -o-linear-gradient(to right, rgba(255, 255, 255, 0), white 65%, white);
+  background: -ms-linear-gradient(to right, rgba(255, 255, 255, 0), white 65%, white);
+  background: linear-gradient(to right, rgba(255, 255, 255, 0), white 65%, white);
+}
+.ellipsis:after {
+  font-style: normal; color: #aaa;
+  font-size:13px;
+  text-align: right;
+}
+
+/* Flow Layout */
+.resource-flow-layout {
+  display: inline-block;
+}
+.resource-flow-layout .resource-card, .resource-flow-layout .resource-card-stack {
+  float: left;
+  position: relative;
+}
+.resource-flow-layout .resource-card-stack > .resource-card {
+  margin-right: 0px !important;
+}
+.resource-flow-layout:after {
+  content: ".";
+  display: block;
+  height: 0;
+  position:relative;
+  clear: both;
+  visibility: hidden;
+}
+.resource-card:hover {
+  cursor: pointer;
+}
+.static .resource-card:hover {
+  cursor: auto;
+}
+.resource-card:hover .card-bg:after {
+  opacity: 0;
+}
+/* disabled to make way for fade/ellipsis truncation,
+   and the plusone moves up.
+.resource-card:hover .card-info .description .text {
+  padding-right: 70px;
+} */
+.resource-card:hover .card-info .description .util {
+  opacity: 1;
+}
+
+/* Carousel Layout */
+/* Carousel styles for landing page */
+.resource-carousel-layout {
+  margin: 20px 0 20px 0;
+  position: relative;
+  overflow: hidden;
+}
+.resource-carousel-layout .slideshow-prev, .resource-carousel-layout .slideshow-next {
+  display: none;
+}
+.resource-carousel-layout .pagination {
+  bottom: 0px;
+}
+.resource-carousel-layout .frame li {
+  position: relative;
+}
+.resource-carousel-layout .frame li .card-bg {
+  height: 300px;
+}
+.resource-carousel-layout .frame li .card-info {
+  padding: 7px 15px 0px 15px;
+  top: 300px;
+}
+.resource-carousel-layout .frame li .card-info .section {
+  font-size: 13px;
+  margin-bottom: 7px;
+}
+.resource-carousel-layout .frame li .card-info .title {
+  font-size: 25px;
+  margin-bottom: 2px;
+}
+.resource-carousel-layout .frame li .card-info .description {
+  font-family: 15px/16px Roboto Condensed, sans-serif;
+}
+.resource-carousel-layout .frame li .card-info .description .text {
+  height: 40px;
+}
+.resource-carousel-layout .frame li .card-info .description .util {
+  bottom:97px;
+  right:4px;
+}
+
+/* Stack Layout */
+.resource-stack-layout {
+  display: inline-block;
+}
+.resource-stack-layout .resource-card-stack {
+  float: left;
+  position: relative;
+}
+.resource-stack-layout .resource-card {
+  margin-bottom: 20px;
+  display: block;
+  position: relative;
+}
+.resource-stack-layout .section-card-menu > .card-info .section, .resource-stack-layout .section-card > .card-info .title {
+  /*text-transform: uppercase;*/
+  color: #898989;
+  font-size: 17px;
+  line-height: 24px;
+  margin-bottom: 6px;
+}
+.resource-stack-layout .section-card {
+  height: 284px;
+}
+.resource-stack-layout .section-card > .card-bg {
+  height: 192px;
+}
+.resource-stack-layout .section-card > .card-info {
+  padding: 4px 12px 6px 12px;
+  top: 192px;
+}
+.resource-stack-layout .section-card > .card-info .section {
+  display: none;
+}
+.resource-stack-layout .section-card > .card-info .title {
+  font-size: 17px;
+  border-bottom: 1px solid #959595;
+  padding-bottom: 0px;
+}
+.resource-stack-layout .section-card > .card-info .description {
+  font-size: 13px;
+  line-height: 15px;
+}
+.resource-stack-layout .section-card > .card-info .description .text {
+  height: 30px;
+}
+.resource-stack-layout .related-card {
+  height: 90px;
+}
+.resource-stack-layout .related-card > .card-bg {
+  left: 0;
+  top: 0;
+  width: 90px;
+  height: 100%;
+  position: absolute;
+  display: block;
+}
+.resource-stack-layout .related-card > .card-info {
+  left: 90px;
+  padding: 4px 12px 4px 12px;
+}
+.resource-stack-layout .related-card > .card-info .section {
+  font-size: 12px;
+  margin-bottom: 1px;
+  display: none;
+}
+.resource-stack-layout .related-card > .card-info .title {
+  font-size: 16px;
+  margin-bottom: -2px;
+  white-space: normal;
+  overflow: visible;
+  text-overflow: ellipsis;
+}
+.resource-stack-layout .related-card > .card-info .title:after {
+  content: url(../images/link-out.png);
+  display: block;
+}
+.resource-stack-layout .related-card > .card-info .description {
+  display: none;
+}
+.resource-stack-layout .section-card-menu {
+  /* Flexible height */
+  display: block;
+  height: auto;
+  width: auto;
+}
+.resource-stack-layout .section-card-menu .card-bg {
+  height: 155px;
+  /* Flexible height */
+  position: relative;
+  display: inline-block;
+  vertical-align: top;
+}
+.resource-stack-layout .section-card-menu .card-info {
+  padding: 4px 12px 0px 12px;
+  /* Flexible height */
+  position: relative;
+  left: auto;
+  top: auto;
+  right: auto;
+  bottom: auto;
+}
+.resource-stack-layout .section-card-menu .card-info ul {
+  list-style: none;
+  margin: 0;
+}
+.resource-stack-layout .section-card-menu .card-info ul li {
+  list-style: none;
+  margin: 0;
+  padding: 15px 0;
+  border-top-width: 1px;
+  border-top-style: solid;
+  border-top-color: #959595;
+}
+.resource-stack-layout .section-card-menu .card-info ul li a, .resource-stack-layout .section-card-menu .card-info ul li a:focus, .resource-stack-layout .section-card-menu .card-info ul li a:link, .resource-stack-layout .section-card-menu .card-info ul li a:visited, .resource-stack-layout .section-card-menu .card-info ul li a:active, .resource-stack-layout .section-card-menu .card-info ul li a:hover {
+  color: #363636 !important;
+}
+.resource-stack-layout .section-card-menu .card-info ul li:first-child {
+  border-top: none;
+}
+.resource-stack-layout .section-card-menu .card-info ul li:hover .title:after {
+  opacity: 1;
+  -webkit-transition: opacity 0.5s;
+  -moz-transition: opacity 0.5s;
+  -o-transition: opacity 0.5s;
+  transition: opacity 0.5s;
+}
+.resource-stack-layout .section-card-menu .card-info ul li:hover .description {
+  max-height: 30px;
+  opacity: 1;
+  -webkit-transition: max-height 0.5s, opacity 1s;
+  -moz-transition: max-height 0.5s, opacity 1s;
+  -o-transition: max-height 0.5s, opacity 1s;
+  transition: max-height 0.5s, opacity 1s;
+}
+.resource-stack-layout .section-card-menu .card-info .title {
+  font-size: 16px;
+  margin-bottom: -2px;
+  position: relative;
+}
+.resource-stack-layout .section-card-menu .card-info .title:after {
+  background: url(../images/stack-arrow-right.png);
+  content: '';
+  opacity: 0;
+  -webkit-transition: opacity 0.25s;
+  -moz-transition: opacity 0.25s;
+  -o-transition: opacity 0.25s;
+  transition: opacity 0.25s;
+  position: absolute;
+  right: 0px;
+  top: 3px;
+  width: 10px;
+  height: 15px;
+}
+.resource-stack-layout .section-card-menu .card-info .title.more {
+  text-transform: uppercase;
+  color: #898989;
+  display: inline-block;
+}
+.resource-stack-layout .section-card-menu .card-info .title.more:after {
+  background: url(../images/stack-arrow-right.png);
+  content: '';
+  display: block;
+  position: absolute;
+  right: -20px;
+  top: 3px;
+  width: 10px;
+  height: 15px;
+}
+.resource-stack-layout .section-card-menu .card-info .description {
+  max-height: 0px;
+  opacity: 0;
+  overflow: hidden;
+  font-size: 13px;
+  line-height: 15px;
+  /* Hover off */
+  -webkit-transition: max-height 0.5s, opacity 0.5s;
+  -moz-transition: max-height 0.5s, opacity 0.5s;
+  -o-transition: max-height 0.5s, opacity 0.5s;
+  transition: max-height 0.5s, opacity 0.5s;
+}
+.resource-stack-layout .section-card-menu .card-info .description .text {
+  height: 30px;
+}
+.resource-stack-layout:after {
+  content: ".";
+  display: block;
+  height: 0;
+  clear: both;
+  visibility: hidden;
+}
+
+/* Generate the flow layout styles for a 3-column 16-col span */
+.resource-flow-layout.col-16 {
+  margin: 0 -14px 0 0;
+  width: 954px;
+}
+.resource-flow-layout.col-16 .resource-card, .resource-flow-layout.col-16 .resource-card-stack {
+  margin: 0 14px 20px 0;
+}
+.resource-flow-layout.col-16 .resource-card-row-stack-last {
+  margin-bottom: 0px !important;
+}
+.resource-flow-layout.col-16 .resource-card-col-stack-last {
+  margin-bottom: 0px !important;
+}
+.resource-flow-layout.col-16 .resource-card-3x6 {
+  width: 145px;
+  height: 284px;
+}
+.resource-flow-layout.col-16 .resource-card-3x12 {
+  width: 145px;
+  height: 588px;
+}
+.resource-flow-layout.col-16 .resource-card-3x18 {
+  width: 145px;
+  height: 892px;
+}
+.resource-flow-layout.col-16 .resource-card-6x6 {
+  width: 304px;
+  height: 284px;
+}
+.resource-flow-layout.col-16 .resource-card-6x12 {
+  width: 304px;
+  height: 588px;
+}
+.resource-flow-layout.col-16 .resource-card-6x18 {
+  width: 304px;
+  height: 892px;
+}
+.resource-flow-layout.col-16 .resource-card-9x6 {
+  width: 463px;
+  height: 284px;
+}
+.resource-flow-layout.col-16 .resource-card-9x12 {
+  width: 463px;
+  height: 588px;
+}
+.resource-flow-layout.col-16 .resource-card-9x18 {
+  width: 463px;
+  height: 892px;
+}
+.resource-flow-layout.col-16 .resource-card-12x6 {
+  width: 622px;
+  height: 284px;
+}
+.resource-flow-layout.col-16 .resource-card-12x12 {
+  width: 622px;
+  height: 588px;
+}
+.resource-flow-layout.col-16 .resource-card-12x18 {
+  width: 622px;
+  height: 892px;
+}
+.resource-flow-layout.col-16 .resource-card-15x6 {
+  width: 781px;
+  height: 284px;
+}
+.resource-flow-layout.col-16 .resource-card-15x12 {
+  width: 781px;
+  height: 588px;
+}
+.resource-flow-layout.col-16 .resource-card-15x18 {
+  width: 781px;
+  height: 892px;
+}
+.resource-flow-layout.col-16 .resource-card-18x6 {
+  width: 940px;
+  height: 284px;
+}
+.resource-flow-layout.col-16 .resource-card-18x12 {
+  width: 940px;
+  height: 420px;
+}
+.resource-flow-layout.col-16 .resource-card-18x18 {
+  width: 940px;
+  height: 892px;
+}
+.resource-flow-layout.col-16 .resource-card-3x2 {
+  width: 145px;
+  height: 95px;
+}
+.resource-flow-layout.col-16 .resource-card-3x2x3 {
+  width: 145px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-16 .resource-card-3x3 {
+  width: 145px;
+  height: 142px;
+}
+.resource-flow-layout.col-16 .resource-card-3x3x2 {
+  width: 145px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-16 .resource-card-6x2 {
+  width: 304px;
+  height: 95px;
+}
+.resource-flow-layout.col-16 .resource-card-6x2x3 {
+  width: 304px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-16 .resource-card-6x3 {
+  width: 304px;
+  height: 142px;
+}
+.resource-flow-layout.col-16 .resource-card-6x3x2 {
+  width: 304px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-16 .resource-card-9x2 {
+  width: 463px;
+  height: 95px;
+}
+.resource-flow-layout.col-16 .resource-card-9x2x3 {
+  width: 463px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-16 .resource-card-9x3 {
+  width: 463px;
+  height: 142px;
+}
+.resource-flow-layout.col-16 .resource-card-9x3x2 {
+  width: 463px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-16 .resource-card-12x2 {
+  width: 622px;
+  height: 95px;
+}
+.resource-flow-layout.col-16 .resource-card-12x2x3 {
+  width: 622px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-16 .resource-card-12x3 {
+  width: 622px;
+  height: 142px;
+}
+.resource-flow-layout.col-16 .resource-card-12x3x2 {
+  width: 622px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-16 .resource-card-15x2 {
+  width: 781px;
+  height: 95px;
+}
+.resource-flow-layout.col-16 .resource-card-15x2x3 {
+  width: 781px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-16 .resource-card-15x3 {
+  width: 781px;
+  height: 142px;
+}
+.resource-flow-layout.col-16 .resource-card-15x3x2 {
+  width: 781px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-16 .resource-card-18x2 {
+  width: 940px;
+  height: 95px;
+}
+.resource-flow-layout.col-16 .resource-card-18x2x3 {
+  width: 940px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-16 .resource-card-18x3 {
+  width: 940px;
+  height: 142px;
+}
+.resource-flow-layout.col-16 .resource-card-18x3x2 {
+  width: 940px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+
+/* Generate the flow layout styles for a 3-column 16-col span */
+.resource-flow-layout.col-12 {
+  margin: 0 -14px 0 0;
+  width: 714px;
+}
+
+.resource-flow-layout.col-12 .resource-card, .resource-flow-layout.col-12 .resource-card-stack {
+  margin: 0 14px 20px 0;
+}
+.resource-flow-layout.col-12 .resource-card-row-stack-last {
+  margin-bottom: 0px !important;
+}
+.resource-flow-layout.col-12 .resource-card-col-stack-last {
+  margin-bottom: 0px !important;
+}
+.resource-flow-layout.col-12 .resource-card-3x6 {
+  width: 105px;
+  height: 284px;
+}
+.resource-flow-layout.col-12 .resource-card-3x12 {
+  width: 105px;
+  height: 588px;
+}
+.resource-flow-layout.col-12 .resource-card-3x18 {
+  width: 105px;
+  height: 892px;
+}
+.resource-flow-layout.col-12 .resource-card-6x6 {
+  width: 224px;
+  height: 284px;
+}
+.resource-flow-layout.col-12 .resource-card-6x12 {
+  width: 224px;
+  height: 588px;
+}
+.resource-flow-layout.col-12 .resource-card-6x18 {
+  width: 224px;
+  height: 892px;
+}
+.resource-flow-layout.col-12 .resource-card-9x6 {
+  width: 343px;
+  height: 284px;
+}
+.resource-flow-layout.col-12 .resource-card-9x12 {
+  width: 343px;
+  height: 588px;
+}
+.resource-flow-layout.col-12 .resource-card-9x18 {
+  width: 343px;
+  height: 892px;
+}
+.resource-flow-layout.col-12 .resource-card-12x6 {
+  width: 462px;
+  height: 284px;
+}
+.resource-flow-layout.col-12 .resource-card-12x12 {
+  width: 462px;
+  height: 588px;
+}
+.resource-flow-layout.col-12 .resource-card-12x18 {
+  width: 462px;
+  height: 892px;
+}
+.resource-flow-layout.col-12 .resource-card-15x6 {
+  width: 581px;
+  height: 284px;
+}
+.resource-flow-layout.col-12 .resource-card-15x12 {
+  width: 581px;
+  height: 588px;
+}
+.resource-flow-layout.col-12 .resource-card-15x18 {
+  width: 581px;
+  height: 892px;
+}
+.resource-flow-layout.col-12 .resource-card-18x6 {
+  width: 700px;
+  height: 284px;
+}
+.resource-flow-layout.col-12 .resource-card-18x12 {
+  width: 700px;
+  height: 420px;
+}
+.resource-flow-layout.col-12 .resource-card-18x18 {
+  width: 700px;
+  height: 892px;
+}
+.resource-flow-layout.col-12 .resource-card-3x2 {
+  width: 105px;
+  height: 95px;
+}
+.resource-flow-layout.col-12 .resource-card-3x2x3 {
+  width: 105px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-12 .resource-card-3x3 {
+  width: 105px;
+  height: 142px;
+}
+.resource-flow-layout.col-12 .resource-card-3x3x2 {
+  width: 105px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-12 .resource-card-6x2 {
+  width: 224px;
+  height: 95px;
+}
+.resource-flow-layout.col-12 .resource-card-6x2x3 {
+  width: 224px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-12 .resource-card-6x3 {
+  width: 224px;
+  height: 142px;
+}
+.resource-flow-layout.col-12 .resource-card-6x3x2 {
+  width: 224px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-12 .resource-card-9x2 {
+  width: 343px;
+  height: 95px;
+}
+.resource-flow-layout.col-12 .resource-card-9x2x3 {
+  width: 343px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-12 .resource-card-9x3 {
+  width: 343px;
+  height: 142px;
+}
+.resource-flow-layout.col-12 .resource-card-9x3x2 {
+  width: 343px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-12 .resource-card-12x2 {
+  width: 462px;
+  height: 95px;
+}
+.resource-flow-layout.col-12 .resource-card-12x2x3 {
+  width: 462px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-12 .resource-card-12x3 {
+  width: 462px;
+  height: 142px;
+}
+.resource-flow-layout.col-12 .resource-card-12x3x2 {
+  width: 462px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-12 .resource-card-15x2 {
+  width: 581px;
+  height: 95px;
+}
+.resource-flow-layout.col-12 .resource-card-15x2x3 {
+  width: 581px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-12 .resource-card-15x3 {
+  width: 581px;
+  height: 142px;
+}
+.resource-flow-layout.col-12 .resource-card-15x3x2 {
+  width: 581px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-12 .resource-card-18x2 {
+  width: 700px;
+  height: 95px;
+}
+.resource-flow-layout.col-12 .resource-card-18x2x3 {
+  width: 700px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-12 .resource-card-18x3 {
+  width: 700px;
+  height: 142px;
+}
+.resource-flow-layout.col-12 .resource-card-18x3x2 {
+  width: 700px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+
+/* Generate the flow layout styles for a 3-column 13-col span */
+
+.resource-flow-layout.col-13 {
+  margin: 0 -14px 0 0;
+  width: 774px;
+}
+.resource-flow-layout.col-13 .resource-card, .resource-flow-layout.col-13 .resource-card-stack {
+  margin: 0 14px 20px 0;
+}
+.resource-flow-layout.col-13 .resource-card-row-stack-last {
+  margin-bottom: 0px !important;
+}
+.resource-flow-layout.col-13 .resource-card-col-stack-last {
+  margin-bottom: 0px !important;
+}
+.resource-flow-layout.col-13 .resource-card-3x6 {
+  width: 115px;
+  height: 284px;
+}
+.resource-flow-layout.col-13 .resource-card-3x12 {
+  width: 115px;
+  height: 588px;
+}
+.resource-flow-layout.col-13 .resource-card-3x18 {
+  width: 115px;
+  height: 892px;
+}
+.resource-flow-layout.col-13 .resource-card-6x6 {
+  width: 244px;
+  height: 284px;
+}
+.resource-flow-layout.col-13 .resource-card-6x12 {
+  width: 244px;
+  height: 588px;
+}
+.resource-flow-layout.col-13 .resource-card-6x18 {
+  width: 244px;
+  height: 892px;
+}
+.resource-flow-layout.col-13 .resource-card-9x6 {
+  width: 373px;
+  height: 284px;
+}
+.resource-flow-layout.col-13 .resource-card-9x12 {
+  width: 373px;
+  height: 588px;
+}
+.resource-flow-layout.col-13 .resource-card-9x18 {
+  width: 373px;
+  height: 892px;
+}
+.resource-flow-layout.col-13 .resource-card-12x6 {
+  width: 502px;
+  height: 284px;
+}
+.resource-flow-layout.col-13 .resource-card-12x12 {
+  width: 502px;
+  height: 588px;
+}
+.resource-flow-layout.col-13 .resource-card-12x18 {
+  width: 502px;
+  height: 892px;
+}
+.resource-flow-layout.col-13 .resource-card-15x6 {
+  width: 631px;
+  height: 284px;
+}
+.resource-flow-layout.col-13 .resource-card-15x12 {
+  width: 631px;
+  height: 588px;
+}
+.resource-flow-layout.col-13 .resource-card-15x18 {
+  width: 631px;
+  height: 892px;
+}
+.resource-flow-layout.col-13 .resource-card-18x6 {
+  width: 760px;
+  height: 284px;
+}
+.resource-flow-layout.col-13 .resource-card-18x12 {
+  width: 760px;
+  height: 420px;
+}
+.resource-flow-layout.col-13 .resource-card-18x18 {
+  width: 760px;
+  height: 892px;
+}
+.resource-flow-layout.col-13 .resource-card-3x2 {
+  width: 115px;
+  height: 95px;
+}
+.resource-flow-layout.col-13 .resource-card-3x2x3 {
+  width: 115px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-13 .resource-card-3x3 {
+  width: 115px;
+  height: 142px;
+}
+.resource-flow-layout.col-13 .resource-card-3x3x2 {
+  width: 115px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-13 .resource-card-6x2 {
+  width: 244px;
+  height: 95px;
+}
+.resource-flow-layout.col-13 .resource-card-6x2x3 {
+  width: 244px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-13 .resource-card-6x3 {
+  width: 244px;
+  height: 142px;
+}
+.resource-flow-layout.col-13 .resource-card-6x3x2 {
+  width: 244px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-13 .resource-card-9x2 {
+  width: 373px;
+  height: 95px;
+}
+.resource-flow-layout.col-13 .resource-card-9x2x3 {
+  width: 373px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-13 .resource-card-9x3 {
+  width: 373px;
+  height: 142px;
+}
+.resource-flow-layout.col-13 .resource-card-9x3x2 {
+  width: 373px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-13 .resource-card-12x2 {
+  width: 502px;
+  height: 95px;
+}
+.resource-flow-layout.col-13 .resource-card-12x2x3 {
+  width: 502px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-13 .resource-card-12x3 {
+  width: 502px;
+  height: 142px;
+}
+.resource-flow-layout.col-13 .resource-card-12x3x2 {
+  width: 502px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-13 .resource-card-15x2 {
+  width: 631px;
+  height: 95px;
+}
+.resource-flow-layout.col-13 .resource-card-15x2x3 {
+  width: 631px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-13 .resource-card-15x3 {
+  width: 631px;
+  height: 142px;
+}
+.resource-flow-layout.col-13 .resource-card-15x3x2 {
+  width: 631px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+.resource-flow-layout.col-13 .resource-card-18x2 {
+  width: 760px;
+  height: 95px;
+}
+.resource-flow-layout.col-13 .resource-card-18x2x3 {
+  width: 760px;
+  height: 90px;
+  margin-bottom: 7px;
+}
+.resource-flow-layout.col-13 .resource-card-18x3 {
+  width: 760px;
+  height: 142px;
+}
+.resource-flow-layout.col-13 .resource-card-18x3x2 {
+  width: 760px;
+  height: 138px;
+  margin-bottom: 8px;
+}
+
+/*
+  The following are styles for cards in the flowlayout above, styled by the number of rows they span
+*/
+/* Single row items, might be simpler to just apply a class */
+.resource-card-3x6 > .card-bg, .resource-card-6x6 > .card-bg, .resource-card-9x6 > .card-bg, .resource-card-12x6 > .card-bg, .resource-card-15x6 > .card-bg, .resource-card-18x6 > .card-bg {
+  height: 192px;
+}
+.resource-card-3x6 > .card-info, .resource-card-6x6 > .card-info, .resource-card-9x6 > .card-info, .resource-card-12x6 > .card-info, .resource-card-15x6 > .card-info, .resource-card-18x6 > .card-info {
+  padding: 4px 12px 6px 12px;
+  top: 192px;
+}
+.resource-card-3x6 > .card-info .section, .resource-card-6x6 > .card-info .section, .resource-card-9x6 > .card-info .section, .resource-card-12x6 > .card-info .section, .resource-card-15x6 > .card-info .section, .resource-card-18x6 > .card-info .section {
+  font-size: 12px;
+  margin-bottom: 1px;
+}
+.resource-card-3x6 > .card-info .title, .resource-card-6x6 > .card-info .title, .resource-card-9x6 > .card-info .title, .resource-card-12x6 > .card-info .title, .resource-card-15x6 > .card-info .title, .resource-card-18x6 > .card-info .title {
+  font-size: 16px;
+  margin-bottom: -2px;
+}
+.resource-card-3x6 > .card-info .description, .resource-card-6x6 > .card-info .description, .resource-card-9x6 > .card-info .description, .resource-card-12x6 > .card-info .description, .resource-card-15x6 > .card-info .description, .resource-card-18x6 > .card-info .description {
+  font-size: 13px;
+  line-height: 15px;
+}
+.resource-card-3x6 > .card-info .description .text, .resource-card-6x6 > .card-info .description .text, .resource-card-9x6 > .card-info .description .text, .resource-card-12x6 > .card-info .description .text, .resource-card-15x6 > .card-info .description .text, .resource-card-18x6 > .card-info .description .text {
+  height: 30px;
+}
+
+/* Double row items */
+.resource-card-3x12 > .card-bg, .resource-card-6x12 > .card-bg, .resource-card-9x12 > .card-bg, .resource-card-12x12 > .card-bg, .resource-card-15x12 > .card-bg, .resource-card-18x12 > .card-bg {
+  height: 320px;
+}
+.resource-card-3x12 > .card-info, .resource-card-6x12 > .card-info, .resource-card-9x12 > .card-info, .resource-card-12x12 > .card-info, .resource-card-15x12 > .card-info, .resource-card-18x12 > .card-info {
+  padding: 4px 12px 6px 12px;
+  top: 320px;
+}
+.resource-card-3x12 > .card-info .section, .resource-card-6x12 > .card-info .section, .resource-card-9x12 > .card-info .section, .resource-card-12x12 > .card-info .section, .resource-card-15x12 > .card-info .section, .resource-card-18x12 > .card-info .section {
+  font-size: 12px;
+  margin-bottom: 1px;
+}
+.resource-card-3x12 > .card-info .title, .resource-card-6x12 > .card-info .title, .resource-card-9x12 > .card-info .title, .resource-card-12x12 > .card-info .title, .resource-card-15x12 > .card-info .title, .resource-card-18x12 > .card-info .title {
+  font-size: 16px;
+  margin-bottom: -2px;
+  white-space: normal;
+}
+.resource-card-3x12 > .card-info .description, .resource-card-6x12 > .card-info .description, .resource-card-9x12 > .card-info .description, .resource-card-12x12 > .card-info .description, .resource-card-15x12 > .card-info .description, .resource-card-18x12 > .card-info .description {
+  font-size: 13px;
+  line-height: 15px;
+}
+
+/* 1/3 row items */
+.resource-card-3x2 > .card-bg, .resource-card-6x2 > .card-bg, .resource-card-9x2 > .card-bg, .resource-card-12x2 > .card-bg, .resource-card-15x2 > .card-bg, .resource-card-18x2 > .card-bg {
+  left: 0;
+  top: 0;
+  width: 90px;
+  height: 100%;
+  position: absolute;
+  display: block;
+}
+.resource-card-3x2 > .card-info, .resource-card-6x2 > .card-info, .resource-card-9x2 > .card-info, .resource-card-12x2 > .card-info, .resource-card-15x2 > .card-info, .resource-card-18x2 > .card-info {
+  left: 90px;
+  padding: 4px 12px 4px 12px;
+  height: 80px;
+  overflow: hidden;
+}
+.resource-card-3x2 > .card-info .section, .resource-card-6x2 > .card-info .section, .resource-card-6x3 > .card-info .section, .resource-card-9x2 > .card-info .section, .resource-card-12x2 > .card-info .section, .resource-card-15x2 > .card-info .section, .resource-card-18x2 > .card-info .section {
+  font-size: 12px;
+  margin-bottom: 1px;
+  /* display: none; */
+}
+.resource-card-3x2 > .card-info .title, .resource-card-6x2 > .card-info .title, .resource-card-9x2 > .card-info .title, .resource-card-12x2 > .card-info .title, .resource-card-15x2 > .card-info .title, .resource-card-18x2 > .card-info .title {
+  font-size: 16px;
+  margin-bottom: -2px;
+  white-space: normal;
+  overflow: visible;
+  text-overflow: ellipsis;
+}
+.resource-card-3x2 > .card-info .title:after, .resource-card-6x2 > .card-info .title:after, .resource-card-9x2 > .card-info .title:after, .resource-card-12x2 > .card-info .title:after, .resource-card-15x2 > .card-info .title:after, .resource-card-18x2 > .card-info .title:after {
+  /* content: url(../images/link-out.png); */
+  display: block;
+}
+.resource-card-3x2 > .card-info .description, .resource-card-6x2 > .card-info .description, .resource-card-9x2 > .card-info .description, .resource-card-12x2 > .card-info .description, .resource-card-15x2 > .card-info .description, .resource-card-18x2 > .card-info .description {
+  display: none;
+}
+
+
+/* Override to show the description instead of the content section */
+.no-section .resource-card-3x2 > .card-info .section,
+.no-section .resource-card-6x2 > .card-info .section {
+  display: none;
+}
+.no-section .resource-card-3x2 > .card-info .description,
+.no-section .resource-card-6x2 > .card-info .description {
+  display: block;
+}
+
+/* 1/2 row items */
+.resource-card-3x3 > .card-bg, .resource-card-6x3 > .card-bg, .resource-card-9x3 > .card-bg, .resource-card-12x3 > .card-bg, .resource-card-15x3 > .card-bg, .resource-card-18x3 > .card-bg {
+  left: 0;
+  top: 0;
+  width: 90px;
+  height: 100%;
+  position: absolute;
+  display: block;
+}
+.resource-card-3x3 > .card-info, .resource-card-6x3 > .card-info, .resource-card-9x3 > .card-info, .resource-card-12x3 > .card-info, .resource-card-15x3 > .card-info, .resource-card-18x3 > .card-info {
+  left: 90px;
+  padding: 4px 12px 0px 12px;
+}
+.resource-card-3x3 > .card-info .section, .resource-card-6x3 > .card-info .section, .resource-card-9x3 > .card-info .section, .resource-card-12x3 > .card-info .section, .resource-card-15x3 > .card-info .section, .resource-card-18x3 > .card-info .section {
+  font-size: 12px;
+  margin-bottom: 1px;
+  display: none;
+}
+.resource-card-3x3 > .card-info .title, .resource-card-6x3 > .card-info .title, .resource-card-9x3 > .card-info .title, .resource-card-12x3 > .card-info .title, .resource-card-15x3 > .card-info .title, .resource-card-18x3 > .card-info .title {
+  font-size: 16px;
+  margin-bottom: -2px;
+  white-space: normal;
+  overflow: visible;
+}
+.resource-card-3x3 > .card-info .description .text, .resource-card-6x3 > .card-info .description .text, .resource-card-9x3 > .card-info .description .text, .resource-card-12x3 > .card-info .description .text, .resource-card-15x3 > .card-info .description .text, .resource-card-18x3 > .card-info .description .text {
+  font-size: 12px;
+  line-height: 15px;
+  padding-right: 0px !important;
+  height: 80px;
+}
+.resource-card-3x3 > .card-info .description .util, .resource-card-6x3 > .card-info .description .util, .resource-card-9x3 > .card-info .description .util, .resource-card-12x3 > .card-info .description .util, .resource-card-15x3 > .card-info .description .util, .resource-card-18x3 > .card-info .description .util {
+  display: none;
+}
+/* placement of plusone */
+.resource-card-6x12 > .card-info .description .util, .resource-card-9x12 > .card-info .description .util, .resource-card-12x12 > .card-info .description .util, .resource-card-15x12 > .card-info .description .util {
+  bottom:2px;
+}
+.resource-card-18x12 > .card-info .description .util {
+  bottom:2px;
+}
+/* Overrides for col-16 6x6 cards linking to local content on landing pages.
+   Suppresses "section" and puts the title above a hairline rule. */
+.landing .card-info .section, .resource-flow-layout.col-16.landing .resource-card-9x6 .card-info .section {
+  display:none;
+}
+.landing  .card-info .title {
+  color: #898989;
+  font-size: 17px;
+  line-height: 24px;
+  margin-bottom: 6px;
+  border-bottom: 1px solid #959595;
+  padding-bottom: 0px;
+}
+.landing .card-info .description {
+  font-size: 13px;
+  line-height: 15px;
+}
+.landing .card-info .description .text {
+height:30px;
+}
+.landing .resource-card-6x6 > .card-info .description .util, .landing .resource-card-9x6 > .card-info .description .util {
+  bottom:2px;
+}
+/*
+  Generate a resource stack layout for a 3 column widget spanning 16 grid cols
+*/
+.resource-stack-layout.col-16 {
+  margin: 0 -14px 0 0;
+  width: 954px;
+}
+.resource-stack-layout.col-16 .resource-card-stack {
+  margin: 0 14px 0 0;
+  width: 304px;
+}
+
+/* Example of card menu tinting */
+.resource-widget[data-section=distribute\/tools] .section-card-menu
+.card-bg:after {
+  background: rgba(126, 55, 148, 0.4) !important;
+}
+.resource-widget[data-section=distribute\/tools] .section-card-menu
+.card-section-icon .icon {
+  background-color: #7e3794 !important;
+}
+.resource-widget[data-section=distribute\/tools] .section-card-menu
+.card-info ul li {
+  border-top-color: #7e3794 !important;
+}
+
+/* tinting for stacks */
+
+div.jd-descr > .resource-widget[data-section=distribute\/tools]
+.section-card-menu .card-info ul li {
+  border-top-color: #7e3794 !important;
+}
+
+
+
+/**
+ * UTILITIES
+ */
+
+
+.border-box {
+  box-sizing: border-box;
+}
+
+.vertical-center-outer {
+  display: table;
+  height: 100%;
+  width: 100%;
+}
+
+.vertical-center-inner {
+  display: table-cell;
+  vertical-align: middle;
+}
+
+/**
+ * TYPE STYLES
+ */
+
+.landing-h1 {
+  font-weight: 100;
+  font-size: 60px;
+  line-height: 78px;
+  text-align: center;
+  letter-spacing: -1px;
+}
+
+.landing-pre-h1 {
+  font-weight: 400;
+  font-size: 28px;
+  color: #93B73F;
+  line-height: 36px;
+  text-align: center;
+  letter-spacing: -1px;
+  text-transform: uppercase;
+
+}
+
+.landing-h1.hero {
+  text-align: left;
+}
+
+.landing-h2 {
+  font-weight: 300;
+  font-size: 42px;
+  line-height: 64px;
+  text-align: center;
+}
+
+.landing-subhead {
+  color: #999999;
+  font-size: 20px;
+  line-height: 28px;
+  font-weight:300;
+  text-align: center;
+}
+.landing-subhead.hero {
+  text-align: left;
+  color: white;
+}
+
+.landing-hero-description {
+  text-align: left;
+  margin: 1em 0;
+}
+
+.landing-hero-description p {
+  font-weight: 300;
+  margin: 0;
+  font-size: 18px;
+  line-height: 24px;
+}
+
+.landing-body .landing-small {
+  font-size: 14px;
+  line-height: 19px;
+}
+
+.landing-body.landing-align-center {
+  text-align: center;
+}
+
+.landing-align-left {
+  text-align: left;
+}
+
+/**
+ * LAYOUT
+ */
+
+#body-content,
+.fullpage,
+#jd-content,
+.jd-descr,
+.landing-body-content {
+  height: 100%;
+}
+
+.landing-section {
+  padding: 80px 10px 80px;
+  width: 100%;
+  margin-left: -10px;
+  text-rendering: optimizeLegibility;
+}
+
+#extending-android-to-wearables {
+  padding-top: 30px;
+}
+
+.landing-short-section {
+  padding: 40px 10px 28px;
+}
+
+.landing-gray-background {
+  background-color: #e9e9e9;
+}
+
+.landing-white-background {
+  background-color: white;
+}
+
+.landing-red-background {
+  color: white;
+  background-color: hsl(8, 70%, 54%);
+}
+
+.landing-subhead-red {
+  color: hsl(8, 71%, 84%);
+  text-align: left;
+}
+
+.landing-subhead-red p {
+  margin-top: 20px;
+}
+
+.landing-hero-container {
+  height: 100%;
+}
+
+
+.preview-hero {
+  height: calc(100% - 110px);
+  min-height: 504px;
+  margin-top: -5px;
+  padding-top: 0;
+  padding-bottom: 0;
+  background-image: url(../../preview/images/hero.jpg);
+  background-size: cover;
+  background-position: right center;
+  color: white;
+  position: relative;
+  overflow: hidden;
+}
+
+.wear-hero {
+  height: calc(100% - 110px);
+  min-height: 504px;
+  margin-top: -5px;
+  padding-top: 0;
+  padding-bottom: 0;
+  background-image: url(../../wear/images/hero.jpg);
+  background-size: cover;
+  background-position: top center;
+  color: white;
+  position: relative;
+  overflow: hidden;
+}
+
+.tv-hero {
+  height: calc(100% - 110px);
+  min-height: 504px;
+  margin-top: -5px;
+  padding-top: 0;
+  padding-bottom: 0;
+  background-image: url(../../tv/images/hero.jpg);
+  background-size: cover;
+  background-position: right center;
+  color: white;
+  position: relative;
+  overflow: hidden;
+}
+
+.auto-hero {
+  height: calc(100% - 110px);
+  min-height: 504px;
+  margin-top: -5px;
+  padding-top: 0;
+  padding-bottom: 0;
+  background-image: url(../../auto/images/hero.jpg);
+  background-size: cover;
+  background-position: right center;
+  color: white;
+  position: relative;
+  overflow: hidden;
+}
+
+.landing-hero-scrim {
+  background: black;
+  opacity: .2;
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  margin-left: -10px;
+}
+
+.landing-hero-wrap {
+  margin: 0 auto;
+  width: 940px;
+  clear: both;
+  height: 100%;
+  position: relative;
+}
+
+.landing-section-header {
+  margin-bottom: 40px;
+}
+
+.landing-hero-wrap .landing-section-header {
+  margin-bottom: 16px;
+}
+
+.landing-body {
+  font-size: 18px;
+  line-height: 24px;
+}
+
+.landing-button {
+  white-space: nowrap;
+  display: inline-block;
+  padding: 16px 32px;
+  font-size: 18px;
+  font-weight: 500;
+  line-height: 24px;
+  cursor: pointer;
+  color: white;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+       -o-user-select: none;
+  user-select: none;
+  -webkit-transition: .2s background-color ease-in-out;
+     -moz-transition: .2s background-color ease-in-out;
+       -o-transition: .2s background-color ease-in-out;
+  transition: .2s background-color ease-in-out;
+}
+
+.landing-primary {
+  background-color: hsl(8, 70%, 44%);
+  color: #f8f8f8;
+}
+
+.landing-button.landing-primary:hover {
+  background-color: hsl(8, 70%, 36%);
+}
+
+.landing-button.landing-primary:active {
+  background-color: hsl(8, 70%, 30%);
+}
+
+.landing-button.landing-secondary {
+  background-color: #2faddb;
+}
+
+.landing-button.landing-secondary:hover {
+  background-color: #09c;
+}
+
+.landing-button.landing-secondary:active {
+  background-color: #3990ab;
+}
+
+a.landing-button,
+a.landing-button:hover,
+a.landing-button:visited {
+  color: white !important;
+}
+
+.landing-video-link {
+  white-space: nowrap;
+  display: inline-block;
+  padding: 16px 32px 16px 82px;
+  font-size: 18px;
+  font-weight: 400;
+  line-height: 24px;
+  cursor: pointer;
+  color: hsla(0, 0%, 100%, .8);
+  -webkit-user-select: none;
+     -moz-user-select: none;
+       -o-user-select: none;
+  user-select: none;
+  -webkit-transition: .2s color ease-in-out;
+     -moz-transition: .2s color ease-in-out;
+       -o-transition: .2s color ease-in-out;
+  transition: .2s color ease-in-out;
+}
+
+.landing-video-link:before {
+  height: 64px;
+  width: 64px;
+  display: inline-block;
+  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAFuklEQVR42u2dXWgcVRSAV9LWtBBTTZVWUhNqEQtq1QeroDRKFRFsROqTYPuo+JCiIoJKFC0USqlUfCiowRcfrBgVUUElefAPkW5T8aeaGn9aRbFsjP0x2cx8PuRMvFxmdjeb2Z17Z8+B85DsZPbO+eaec3/OPSkABdXsVI2gABSAqgJQAKoKQAGoKgAFoKoAFICqAlAAqgpAAai6DqDRAiwDeoFtwB7gPaAInABKwKToCWAMeB/YDdwJrAWWNLh9+QMAXABsBQ4A3wFTwAxQBmaBAAhjNJDPy3L938BXwAvArUCHAkh+kCXAVcA+YBw4bRg7MngtkgTlDPA98CywHmhTAP8/xCbgVeAvMZZpwDQllN7xB/AysKGlAQAXAvuBkzW85UVgCBgENlfQQbmuWAXELPAnsAvoaikAQBtwh/j3coLhS2LIfqCzzu/plL8fkvvFgZiR4L2lHrfkHQBgpQTFUwmGnwC212v0KjC2y/3jQPwDPA+05xYAcBHwubx1YZzhC02QBBBRbxgBzssdAOBy4JgRZE0ZTPuNr7FHDCbEhqNAd24AAN0yUbID7QSwsZChABut3hANXY8Bq70HIMb/Ocb4w81+66v0hmGrN0QQ1ngLQJYRvpWHMWWo4KDIaMnuCcVKgdlZAGL8t2J8vpPGrwChDLyWBMFlAA8D0z4ZvwKEs8D93gCQEc9Jy/jFgkdizaRDGUSs8wXAu1bQLQE9ngHosWbPAXDQeQAypT9rBd3+gociyxi2K9riLABZUj5iuZ6RgsciM2OzFxw2A7JrAO6VwGtKTwpG+Anoy9AVmb3gDHCPcwCAFcChRox6jPu9CazMeFQUAKNRL3AJwE2yopjq228BQPZ/d2bcCyaBTa4BeNGa8Q6naIA4GQWubiKEYWvBbp8zAGQt5VfL/fQ3GEAkTzXDLVkjokA2k5a7AuA2GaLNj/tTfvhq0pQgbcwLQtlQusYVALtlzSR191MjADNI9zbJDZWBR10BMGr5/4GMADQ0SAMDlht62xUAxy0AmzMEEMnhtIO0ZF2YAH5wITd0hQw/5wE04M1bjDyXZpC2hqMlYGnWAHqBf40APOEYgChI35VSWyasWfGqrAH0WVkOIw4CSC1IG2tDoSy7XJE1gPs8ArDoIG0BmJGk30wBDHgGYFFBOgbAtqwB7GxxAHerC8rOBU0Dt2gQzjYIb8gawDor+6HVhqFdrkzEwhabiAVOTMSkUb+06FLEUVfWgj5q0cW4g64AeNo66ZLlcnTDNmesBN4y8KArAG6QU42ttCEzBVzpCoAO4EfLDeV5SzIEvgHaXdqUP2BlQud1Ux55zj2uZUX02cPRnKalRLmu17qYmPWF5YbymJgVAh8Ay5wCII3ZEZOYm6fURGT2u9X43Mnk3CDHybmfmRVYXExPv9nKEcpLejqSC3SjdY2TBzTesHqB7wc0onTEV2KucxLApXKkJy9HlAI5anuJFwCkYQ/EuCJfD+mdBnYkXOssgHY53un7MdVZ4CVgqVcADAhjMafkfTioHc14P04yvvMApIEXy5F/+7S8y6UKolPyR4BVVf7Wi2IdawwIPhTrmAW+rmZ8bwBIQ7vloXwoVzNWS6UUrwAYy9YfOlqwKZDkgneA5Qu4l3cly84F9sqGhislywLmaozuYoGFXr0DII1ukxP1hxJ6QzR7HqLxRfumZaRzXZ3f4XXZyi7gCeB3kqsnzs+kSb9s5XHgMeD8RTxDLgq3rmeuYuFvNYCoR8wqujNi+L3UWBcu9wAMt3QZ8LiMlk5RuU50teq6kcEDgTolveIRYHUQBOek1O5cFu/ukLz7/ZJgNSm+OirebWpgaPS7slxfAr4EngGuX8jopqUBxGzyrAVuB54EXgc+lV4yLhO8cfn5E+ZqUD8kBu9sQvv0Hzj4rmoEBaAAVBWAAlBVAApAVQEoAFUFoABUFYACUFUACkC1CfofXVRJocowZVYAAAAASUVORK5CYII=);
+  background-size: contain;
+  position: absolute;
+  content: "";
+  opacity: .7;
+  margin-top: -19px;
+  margin-left: -64px;
+  -webkit-transition: .2s opacity ease-in-out;
+     -moz-transition: .2s opacity ease-in-out;
+       -o-transition: .2s opacity ease-in-out;
+  transition: .2s opacity ease-in-out;
+}
+
+.landing-video-link:hover {
+  color: hsla(0, 0%, 100%, 1);
+}
+
+.landing-video-link:hover:before {
+  opacity: 1;
+}
+
+.landing-social-image {
+  float: left;
+  margin-right: 14px;
+  height: 64px;
+  width: 64px;
+}
+
+.landing-social-copy {
+  padding-left: 78px;
+}
+
+.landing-scroll-down-affordance {
+  position: absolute;
+  bottom: 0;
+  width: 100%;
+  text-align: center;
+  z-index: 10;
+}
+
+.landing-down-arrow {
+  padding: 24px;
+  display: inline-block;
+  opacity: .5;
+  -webkit-transition: .2s opacity ease-in-out;
+     -moz-transition: .2s opacity ease-in-out;
+       -o-transition: .2s opacity ease-in-out;
+  transition: .2s opacity ease-in-out;
+
+  -webkit-animation-name: pulse-opacity;
+  -webkit-animation-duration: 4s;
+}
+
+.landing-down-arrow:hover {
+  opacity: 1;
+}
+
+.landing-down-arrow img {
+  height: 28px;
+  width: 28px;
+  margin: 0 auto;
+  display: block;
+}
+
+.landing-divider {
+  display: inline-block;
+  height: 2px;
+  background-color: white;
+  position: relative;
+  margin: 10px 0;
+}
+
+/* 3 CLOLUMN LAYOUT */
+
+.landing-breakout {
+  margin-top: 40px;
+  margin-bottom: 40px;
+}
+
+.landing-breakout img {
+  margin-bottom: 20px;
+}
+
+.landing-partners img {
+  margin-bottom: 20px;
+}
+
+.landing-breakout p {
+  padding: 0 23px;
+}
+
+.landing-breakout.landing-partners img {
+  margin-bottom: 20px;
+}
+
+.col-3-wide {
+  display: inline;
+  float: left;
+  margin-left: 10px;
+  margin-right: 10px;
+}
+
+.col-3-wide {
+  width: 302px;
+}
+
+/**
+ * ANIMATION
+ */
+
+@-webkit-keyframes pulse-opacity {
+  0% {
+    opacity: .5;
+  }
+  20% {
+    opacity: .5;
+  }
+  40% {
+    opacity: 1;
+  }
+  60% {
+    opacity: .5;
+  }
+  80% {
+    opacity: 1;
+  }
+  100% {
+    opacity: .5;
+  }
+}
+
+
+
+/**
+ * VIDEO
+ */
+
+#video-container {
+  display:none;
+  position:fixed;
+  top:0;
+  left:-10px;
+  width:102%;
+  height:100%;
+  background-color:rgba(0,0,0,0.7);
+  z-index:99;
+}
+
+#video-frame {
+  width:940px;
+  height:526.4px;
+  margin:80px auto 0;
+  display:none;
+}
+
+.video-close {
+cursor: pointer;
+position: relative;
+left: 940px;
+top: 0;
+pointer-events: all;
+}
+
+#icon-video-close {
+background-image: url("../images/close.png");
+background-position: 0 0;
+height: 36px;
+width: 36px;
+display:block;
+}
+
+
+
+
+/******************
+Styles for d.a.c/index:
+*******************/
+
+
+
+/* Generic full screen carousel styling to be used across pages. */
+.fullscreen-carousel {
+  margin: 0 -10px;
+  width: 100%;
+  overflow: hidden;
+  position: relative;
+}
+
+.fullscreen-carousel-content {
+  width: 100%;
+  height: 100%;
+  position: relative;
+  display: table; /* For vertical centering */
+}
+
+.fullscreen-carousel .vcenter {
+  display: table-cell;
+  vertical-align: middle;
+  position: relative;
+}
+
+.fullscreen-carousel .vcenter > div {
+  margin: 10px auto;
+}
+
+/* Styles for the full-bleed hero image type. */
+.fullscreen-carousel .hero, .fullscreen-carousel .hero h1 {
+  color: #fff;
+}
+
+.fullscreen-carousel .hero h1 {
+  font-weight: 300;
+  font-size: 60px;
+  line-height: 68px;
+  letter-spacing: -1px;
+  margin-top: 0;
+}
+
+.fullscreen-carousel .hero p {
+  font-weight: 300;
+  font-size: 18px;
+  line-height: 24px;
+  -webkit-font-smoothing: antialiased;
+}
+
+.fullscreen-carousel .hero .hero-bg {
+  background-size: cover;
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  left: 0px;
+  top: 0px;
+}
+
+
+/* Full screen carousel styling for the resource flow layout type of content */
+.fullscreen-carousel .resource-flow-layout:after {
+  height: 0; /* Dont know why this is set at 10 in default.css */
+}
+
+.fullscreen-carousel .resource-flow-layout {
+  margin-bottom: 20px;
+}
+
+
+
+/* Generic Tab carousel styling to be used across multiple pages. */
+
+.tab-carousel .tab-nav {
+  list-style: none;
+  position: relative;
+  text-align: center;
+}
+
+.tab-carousel .tab-nav li {
+  display: inline-block;
+  font-size: 22px;
+  font-weight: 400;
+  line-height: 50px;
+  list-style: none;
+  margin: 0;
+  padding: 0 25px;
+  position: relative;
+}
+
+.tab-carousel .tab-nav li a,
+.tab-carousel .tab-nav li a:hover {
+  color: #333 !important;
+  padding: 10px 10px 13px 10px;
+  position: relative;
+  z-index: 1000;
+}
+
+.tab-carousel .tab-nav li:after {
+  background: #ddd;
+  bottom: 0;
+  content: '';
+  height: 4px;
+  left: 0;
+  position: absolute;
+  width: 100%;
+  z-index: 0;
+}
+
+.tab-carousel .tab-nav .highlight {
+  position: absolute;
+  height: 4px;
+  width: 100px;
+  bottom: 0;
+  background: #33b5e5;
+}
+
+.tab-carousel .tab-carousel-content {
+  position: relative;
+  overflow: hidden;
+  white-space: nowrap;
+}
+
+.tab-carousel .tab-carousel-content [data-tab] {
+  display: inline-block;
+  white-space: normal;
+}
+
+
+
+/*
+  Resource styling for the tab carousel. The tab carousel contains either
+  a 3 column layout of resources or a single full-width resource. The
+  latter has the 18x12 class applied to it and can be styled differently
+  that way.
+*/
+
+.tab-carousel .resource .image {
+  width: 100%;
+  height: 250px;
+  background-repeat: no-repeat;
+  background-size: contain;
+  background-position: 50% 50%;
+}
+
+.tab-carousel .resource .info .title {
+  font-size: 18px;
+  line-height: 24px;
+}
+
+.tab-carousel .resource .info .summary,
+.tab-carousel .resource .info .cta {
+  line-height: 24px;
+  font-size: 16px;
+}
+
+.tab-carousel .resource-card-18x12 {
+  position: relative;
+  padding-left: 450px;
+  box-sizing: border-box;
+  display: table-cell;
+  vertical-align: middle;
+}
+
+.tab-carousel .resource-card-18x12 .image {
+  position: absolute;
+  width: 420px;
+  height: 100%;
+  left: 0;
+  top: 0;
+}
+
+.tab-carousel .resource-card-18x12 .info {
+  display: inline-block;
+}
+
+.tab-carousel .resource-card-18x12 .info .title {
+  margin-bottom: 26px;
+}
+
+
+
+
+
+/*
+   Styles for the entity link used in the actions bar and in the cta of
+   the resources that appear in the tab carousel.
+*/
+.actions-bar a:after,
+.resource .cta:after {
+  content: '›';
+  font-weight: 400;
+  font-size: 22px;
+  left: 5px;
+  line-height: 1;
+  position: relative;
+  top: 1px;
+  transition: left 190ms ease-out;
+}
+
+.actions-bar a:hover:after,
+.resource .cta:hover:after {
+  left: 10px;
+}
+
+
+
+
+/*
+  Styles for the actions bar.
+*/
+.actions-bar {
+  background: #9acd00;
+  margin: 0 -10px;
+  text-align: center;
+}
+
+.actions-bar .actions {
+  padding: 30px 0 30px;
+  text-align: justify;
+  font-size: 0.1px;
+  line-height: 0.1px;
+  margin: 0 10px 0 0;
+}
+
+.actions-bar .actions:after {
+  content: '';
+  width: 100%;
+  display: inline-block;
+}
+
+.actions-bar .actions > div {
+  display: inline-block;
+}
+
+.actions-bar a {
+  font-size: 21px;
+  line-height: 27px;
+  color: #fff;
+  font-weight: 300;
+  -webkit-font-smoothing: antialiased;
+}
+
+.actions-bar a:after {
+  top: 0px;
+  font-size: 22px;
+}
+
+.actions-bar a:hover {
+  color: #fff !important;
+}
+
+
+
+
+
+/*
+  Specific styles for new home page layout of the carousels.
+*/
+
+/* Big blue button */
+a.home-new-cta-btn,
+.home-new-carousel-1 .resource-card-18x6 .cta {
+  white-space: nowrap;
+  display: inline-block;
+  padding: 14px 32px;
+  font-size: 18px;
+  font-weight: 500;
+  line-height: 24px;
+  cursor: pointer;
+  background: #33b5e6;
+  border-radius: 4px;
+  margin-top: 20px;
+  color: #fff;
+  transition: 0.2s background-color ease-in-out;
+}
+
+.home-new-carousel-1 .resource-card-18x6 .cta:after {
+  display: none; /* Hide the entity for this button */
+}
+
+a.home-new-cta-btn:hover,
+.home-new-carousel-1 .resource-card-18x6 .cta:hover {
+  color: #fff !important;
+  background: #2d9fca;
+}
+
+.home-new-carousel-1 .resource-card-18x6 .cta {
+  position: absolute;
+  bottom: 20px;
+  left: 16px;
+}
+
+/* Fullscreen carousel. */
+.home-new-carousel-1 {
+  max-height: 700px; /* Set max height so doesn't get too long */
+}
+
+.home-new-carousel-1 .fullscreen-carousel-content {
+  min-height: 450px;  /* Set min height for all content */
+}
+
+.home-new-carousel-1 .hero {
+  background: #000;
+}
+
+.home-new-carousel-1 .hero-bg {
+  background-image: url(/home-new/images/hero.jpg);
+  background-position: right center;
+  opacity: 0.85;
+}
+
+/*
+  Styling for special top card of full screen layout resource layout.
+  We need to specifically style the 18x6 card to adjust its size and layout,
+  since it's not a standard card, not sure if this is unique to the home page
+  layout or should be namespaced within the fullscreen-carousel container.
+*/
+.home-new-carousel-1 .resource-flow-layout.col-16 .resource-card-18x6 {
+  height: 320px;
+  background-color:#F9F9F9;
+  border-radius: 0px;
+  box-shadow: 0px 0px 0px rgba(0, 0, 0, 0);
+
+}
+
+.home-new-carousel-1 .resource-card-18x6 .card-bg {
+  width: 636px;
+  height: 100%;
+}
+
+.home-new-carousel-1 .resource-card-18x6 .card-info {
+  right: 0px;
+  left: 636px;
+  height: 100%;
+  top: 0px;
+  padding: 15px 22px;
+}
+
+.home-new-carousel-1 .resource-card-18x6 .card-info .util {
+  display: none;
+}
+
+.home-new-carousel-1 .resource-card-18x6 .card-info .title {
+  font-size: 20px;
+  font-weight: 500;
+  margin-top: 15px;
+  margin-bottom: 15px;
+}
+
+.home-new-carousel-1 .resource-card-18x6 .card-info .text {
+  font-size: 15px;
+  line-height: 21px;
+}
+
+
+/* Tabbed carousel. */
+.home-new-carousel-2 {
+  margin: 35px auto 100px auto;
+}
+
+.home-new-carousel-2 h1 {
+  font-size: 47px;
+  font-weight: 100;
+  line-height: 54px;
+  text-align: center;
+}
+
+.annotation-message {
+    display: block;
+    font-style: italic;
+    color: #F80;
+}
diff --git a/tools/droiddoc/templates-sdk/assets/css/fullscreen.css b/tools/droiddoc/templates-sdk/assets/css/fullscreen.css
index 71cf65b..7912e34 100644
--- a/tools/droiddoc/templates-sdk/assets/css/fullscreen.css
+++ b/tools/droiddoc/templates-sdk/assets/css/fullscreen.css
@@ -170,7 +170,7 @@
   max-width: 100%;
 }
 
-#nav-x .wrap,
+#header-wrapper #nav-x div.wrap,
 #searchResults.wrap {
     max-width:100%;
 }
@@ -184,9 +184,17 @@
   left:20px; /* !important ... for IE i think */
 }
 
+#sticky-header {
+  padding: 0 20px;
+}
 
+#sticky-header > div {
+  width: 100%;
+}
 
-
+.sticky-menu {
+  width:100%;
+  left:-20px;
 }
 
 .col-right {
diff --git a/tools/droiddoc/templates-sdk/assets/images/android.png b/tools/droiddoc/templates-sdk/assets/images/android.png
new file mode 100644
index 0000000..4040f3f
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/assets/images/android.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk/assets/images/breadcrumb.png b/tools/droiddoc/templates-sdk/assets/images/breadcrumb.png
new file mode 100644
index 0000000..407a318
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/assets/images/breadcrumb.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk/assets/images/dac_logo@2x.png b/tools/droiddoc/templates-sdk/assets/images/dac_logo@2x.png
new file mode 100644
index 0000000..0f2784d
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/assets/images/dac_logo@2x.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk/assets/images/link-out.png b/tools/droiddoc/templates-sdk/assets/images/link-out.png
new file mode 100644
index 0000000..aa55f9a
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/assets/images/link-out.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk/assets/images/preview.png b/tools/droiddoc/templates-sdk/assets/images/preview.png
new file mode 100644
index 0000000..e5856db
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/assets/images/preview.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk/assets/images/resource-card-default-android.jpg b/tools/droiddoc/templates-sdk/assets/images/resource-card-default-android.jpg
new file mode 100644
index 0000000..8050744
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/assets/images/resource-card-default-android.jpg
Binary files differ
diff --git a/tools/droiddoc/templates-sdk/assets/images/stack-arrow-right.png b/tools/droiddoc/templates-sdk/assets/images/stack-arrow-right.png
new file mode 100644
index 0000000..46d6a50
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/assets/images/stack-arrow-right.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk/assets/images/styles/device_wear_square.png b/tools/droiddoc/templates-sdk/assets/images/styles/device_wear_square.png
new file mode 100644
index 0000000..077a7e6
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/assets/images/styles/device_wear_square.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk/assets/images/styles/device_wear_square_small.png b/tools/droiddoc/templates-sdk/assets/images/styles/device_wear_square_small.png
new file mode 100644
index 0000000..e7e1540
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/assets/images/styles/device_wear_square_small.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk/assets/js/docs.js b/tools/droiddoc/templates-sdk/assets/js/docs.js
index 6630bf9..2824a3d 100644
--- a/tools/droiddoc/templates-sdk/assets/js/docs.js
+++ b/tools/droiddoc/templates-sdk/assets/js/docs.js
@@ -19,7 +19,6 @@
 
 /******  ON LOAD SET UP STUFF *********/
 
-var navBarIsFixed = false;
 $(document).ready(function() {
 
   // load json file for JD doc search suggestions
@@ -64,7 +63,12 @@
   $('.scroll-pane').jScrollPane( {verticalGutter:0} );
 
   // add HRs below all H2s (except for a few other h2 variants)
-  $('h2').not('#qv h2').not('#tb h2').not('.sidebox h2').not('#devdoc-nav h2').not('h2.norule').css({marginBottom:0}).after('<hr/>');
+  $('h2').not('#qv h2')
+         .not('#tb h2')
+         .not('.sidebox h2')
+         .not('#devdoc-nav h2')
+         .not('h2.norule').css({marginBottom:0})
+         .after('<hr/>');
 
   // set up the search close button
   $('.search .close').click(function() {
@@ -167,10 +171,24 @@
   // highlight Design tab
   if ($("body").hasClass("design")) {
     $("#header li.design a").addClass("selected");
+    $("#sticky-header").addClass("design");
 
+  // highlight About tabs
+  } else if ($("body").hasClass("about")) {
+    var rootDir = pagePathOriginal.substring(1,pagePathOriginal.indexOf('/', 1));
+    if (rootDir == "about") {
+      $("#nav-x li.about a").addClass("selected");
+    } else if (rootDir == "wear") {
+      $("#nav-x li.wear a").addClass("selected");
+    } else if (rootDir == "tv") {
+      $("#nav-x li.tv a").addClass("selected");
+    } else if (rootDir == "auto") {
+      $("#nav-x li.auto a").addClass("selected");
+    }
   // highlight Develop tab
   } else if ($("body").hasClass("develop") || $("body").hasClass("google")) {
     $("#header li.develop a").addClass("selected");
+    $("#sticky-header").addClass("develop");
     // In Develop docs, also highlight appropriate sub-tab
     var rootDir = pagePathOriginal.substring(1,pagePathOriginal.indexOf('/', 1));
     if (rootDir == "training") {
@@ -195,12 +213,34 @@
   // highlight Distribute tab
   } else if ($("body").hasClass("distribute")) {
     $("#header li.distribute a").addClass("selected");
+    $("#sticky-header").addClass("distribute");
+
+    var baseFrag = pagePathOriginal.indexOf('/', 1) + 1;
+    var secondFrag = pagePathOriginal.substring(baseFrag, pagePathOriginal.indexOf('/', baseFrag));
+    if (secondFrag == "users") {
+      $("#nav-x li.users a").addClass("selected");
+    } else if (secondFrag == "engage") {
+      $("#nav-x li.engage a").addClass("selected");
+    } else if (secondFrag == "monetize") {
+      $("#nav-x li.monetize a").addClass("selected");
+    } else if (secondFrag == "tools") {
+      $("#nav-x li.disttools a").addClass("selected");
+    } else if (secondFrag == "stories") {
+      $("#nav-x li.stories a").addClass("selected");
+    } else if (secondFrag == "essentials") {
+      $("#nav-x li.essentials a").addClass("selected");
+    } else if (secondFrag == "googleplay") {
+      $("#nav-x li.googleplay a").addClass("selected");
+    }
+  } else if ($("body").hasClass("about")) {
+    $("#sticky-header").addClass("about");
   }
 
   // set global variable so we can highlight the sidenav a bit later (such as for google reference)
   // and highlight the sidenav
   mPagePath = pagePath;
   highlightSidenav();
+  buildBreadcrumbs();
 
   // set up prev/next links if they exist
   var $selNavLink = $('#nav').find('a[href="' + pagePath + '"]');
@@ -215,7 +255,7 @@
     var crossBoundaries = ($("body.design").length > 0) || ($("body.guide").length > 0) ? true :
 false; // navigate across topic boundaries only in design docs
     if ($prevListItem.length) {
-      if ($prevListItem.hasClass('nav-section')) {
+      if ($prevListItem.hasClass('nav-section') || crossBoundaries) {
         // jump to last topic of previous section
         $prevLink = $prevListItem.find('a:last');
       } else if (!$selListItem.hasClass('nav-section')) {
@@ -238,7 +278,6 @@
     // set up next links
     var $nextLink = [];
     var startClass = false;
-    var training = $(".next-class-link").length; // decides whether to provide "next class" link
     var isCrossingBoundary = false;
 
     if ($selListItem.hasClass('nav-section') && $selListItem.children('div.empty').length == 0) {
@@ -265,13 +304,15 @@
       if ($nextLink.length == 0) {
         isCrossingBoundary = true;
         // no more topics in this section, jump to the first topic in the next section
-        $nextLink = $selListItem.parents('li:eq(0)').next('li.nav-section').find('a:eq(0)');
+        $nextLink = $selListItem.parents('li:eq(0)').next('li').find('a:eq(0)');
         if (!$nextLink.length) {  // Go up another layer to look for next page (lesson > class > course)
           $nextLink = $selListItem.parents('li:eq(1)').next('li.nav-section').find('a:eq(0)');
           if ($nextLink.length == 0) {
             // if that doesn't work, we're at the end of the list, so disable NEXT link
             $('.next-page-link').attr('href','').addClass("disabled")
                                 .click(function() { return false; });
+            // and completely hide the one in the footer
+            $('.content-footer .next-page-link').hide();
           }
         }
       }
@@ -290,13 +331,19 @@
       $('.next-page-link').attr('href','')
                           .removeClass("hide").addClass("disabled")
                           .click(function() { return false; });
+      // and completely hide the one in the footer
+      $('.content-footer .next-page-link').hide();
       if ($nextLink.length) {
         $('.next-class-link').attr('href',$nextLink.attr('href'))
-                             .removeClass("hide").append($nextLink.html());
+                             .removeClass("hide")
+                             .append(": " + $nextLink.html());
         $('.next-class-link').find('.new').empty();
       }
     } else {
-      $('.next-page-link').attr('href', $nextLink.attr('href')).removeClass("hide");
+      $('.next-page-link').attr('href', $nextLink.attr('href'))
+                          .removeClass("hide");
+      // for the footer link, also add the next page title
+      $('.content-footer .next-page-link').append(": " + $nextLink.html());
     }
 
     if (!startClass && $prevLink.length) {
@@ -308,14 +355,6 @@
       }
     }
 
-    // If this is a training 'article', there should be no prev/next nav
-    // ... if the grandparent is the "nav" ... and it has no child list items...
-    if (training && $selListItem.parents('ul').eq(1).is('[id="nav"]') &&
-        !$selListItem.find('li').length) {
-      $('.next-page-link,.prev-page-link').attr('href','').addClass("disabled")
-                          .click(function() { return false; });
-    }
-
   }
 
 
@@ -323,7 +362,20 @@
   // Set up the course landing pages for Training with class names and descriptions
   if ($('body.trainingcourse').length) {
     var $classLinks = $selListItem.find('ul li a').not('#nav .nav-section .nav-section ul a');
-    var $classDescriptions = $classLinks.attr('description');
+
+    // create an array for all the class descriptions
+    var $classDescriptions = new Array($classLinks.length);
+    var lang = getLangPref();
+    $classLinks.each(function(index) {
+      var langDescr = $(this).attr(lang + "-description");
+      if (typeof langDescr !== 'undefined' && langDescr !== false) {
+        // if there's a class description in the selected language, use that
+        $classDescriptions[index] = langDescr;
+      } else {
+        // otherwise, use the default english description
+        $classDescriptions[index] = $(this).attr("description");
+      }
+    });
 
     var $olClasses  = $('<ol class="class-list"></ol>');
     var $liClass;
@@ -335,7 +387,7 @@
     $classLinks.each(function(index) {
       $liClass  = $('<li></li>');
       $h2Title  = $('<a class="title" href="'+$(this).attr('href')+'"><h2>' + $(this).html()+'</h2><span></span></a>');
-      $pSummary = $('<p class="description">' + $(this).attr('description') + '</p>');
+      $pSummary = $('<p class="description">' + $classDescriptions[index] + '</p>');
 
       $olLessons  = $('<ol class="lesson-list"></ol>');
 
@@ -374,7 +426,7 @@
     var stylesheet = $('link[rel="stylesheet"][class="fullscreen"]');
     setNavBarLeftPos(); // do this even if sidenav isn't fixed because it could become fixed
     // make sidenav behave when resizing the window and side-scolling is a concern
-    if (navBarIsFixed) {
+    if (sticky) {
       if ((stylesheet.attr("disabled") == "disabled") || stylesheet.length == 0) {
         updateSideNavPosition();
       } else {
@@ -385,70 +437,6 @@
   });
 
 
-  // Set up fixed navbar
-  var prevScrollLeft = 0; // used to compare current position to previous position of horiz scroll
-  $(window).scroll(function(event) {
-    if ($('#side-nav').length == 0) return;
-    if (event.target.nodeName == "DIV") {
-      // Dump scroll event if the target is a DIV, because that means the event is coming
-      // from a scrollable div and so there's no need to make adjustments to our layout
-      return;
-    }
-    var scrollTop = $(window).scrollTop();
-    var headerHeight = $('#header').outerHeight();
-    var subheaderHeight = $('#nav-x').outerHeight();
-    var searchResultHeight = $('#searchResults').is(":visible") ?
-                             $('#searchResults').outerHeight() : 0;
-    var totalHeaderHeight = headerHeight + subheaderHeight + searchResultHeight;
-    // we set the navbar fixed when the scroll position is beyond the height of the site header...
-    var navBarShouldBeFixed = scrollTop > totalHeaderHeight;
-    // ... except if the document content is shorter than the sidenav height.
-    // (this is necessary to avoid crazy behavior on OSX Lion due to overscroll bouncing)
-    if ($("#doc-col").height() < $("#side-nav").height()) {
-      navBarShouldBeFixed = false;
-    }
-
-    var scrollLeft = $(window).scrollLeft();
-    // When the sidenav is fixed and user scrolls horizontally, reposition the sidenav to match
-    if (navBarIsFixed && (scrollLeft != prevScrollLeft)) {
-      updateSideNavPosition();
-      prevScrollLeft = scrollLeft;
-    }
-
-    // Don't continue if the header is sufficently far away
-    // (to avoid intensive resizing that slows scrolling)
-    if (navBarIsFixed && navBarShouldBeFixed) {
-      return;
-    }
-
-    if (navBarIsFixed != navBarShouldBeFixed) {
-      if (navBarShouldBeFixed) {
-        // make it fixed
-        var width = $('#devdoc-nav').width();
-        $('#devdoc-nav')
-            .addClass('fixed')
-            .css({'width':width+'px'})
-            .prependTo('#body-content');
-        // add neato "back to top" button
-        $('#devdoc-nav a.totop').css({'display':'block','width':$("#nav").innerWidth()+'px'});
-
-        // update the sidenaav position for side scrolling
-        updateSideNavPosition();
-      } else {
-        // make it static again
-        $('#devdoc-nav')
-            .removeClass('fixed')
-            .css({'width':'auto','margin':''})
-            .prependTo('#side-nav');
-        $('#devdoc-nav a.totop').hide();
-      }
-      navBarIsFixed = navBarShouldBeFixed;
-    }
-
-    resizeNav(250); // pass true in order to delay the scrollbar re-initialization for performance
-  });
-
-
   var navBarLeftPos;
   if ($('#devdoc-nav').length) {
     setNavBarLeftPos();
@@ -522,7 +510,11 @@
     }
   }
 
+  // Resize once loading is finished
   resizeNav();
+  // Check if there's an anchor that we need to scroll into view.
+  // A delay is needed, because some browsers do not immediately scroll down to the anchor
+  window.setTimeout(offsetScrollForSticky, 100);
 
   /* init the language selector based on user cookie for lang */
   loadLangPref();
@@ -593,6 +585,28 @@
   });
 }
 
+
+/** Create the list of breadcrumb links in the sticky header */
+function buildBreadcrumbs() {
+  var $breadcrumbUl =  $("#sticky-header ul.breadcrumb");
+  // Add the secondary horizontal nav item, if provided
+  var $selectedSecondNav = $("div#nav-x ul.nav-x a.selected").clone().removeClass("selected");
+  if ($selectedSecondNav.length) {
+    $breadcrumbUl.prepend($("<li>").append($selectedSecondNav))
+  }
+  // Add the primary horizontal nav
+  var $selectedFirstNav = $("div#header-wrap ul.nav-x a.selected").clone().removeClass("selected");
+  // If there's no header nav item, use the logo link and title from alt text
+  if ($selectedFirstNav.length < 1) {
+    $selectedFirstNav = $("<a>")
+        .attr('href', $("div#header .logo a").attr('href'))
+        .text($("div#header .logo img").attr('alt'));
+  }
+  $breadcrumbUl.prepend($("<li>").append($selectedFirstNav));
+}
+
+
+
 /** Highlight the current page in sidenav, expanding children as appropriate */
 function highlightSidenav() {
   // if something is already highlighted, undo it. This is for dynamic navigation (Samples index)
@@ -705,9 +719,8 @@
   // Then figure out based on scroll position whether the header is visible
   var windowHeight = $window.height();
   var scrollTop = $window.scrollTop();
-  var headerHeight = $('#header').outerHeight();
-  var subheaderHeight = $('#nav-x').outerHeight();
-  var headerVisible = (scrollTop < (headerHeight + subheaderHeight));
+  var headerHeight = $('#header-wrapper').outerHeight();
+  var headerVisible = scrollTop < stickyTop;
 
   // get the height of space between nav and top of window.
   // Could be either margin or top position, depending on whether the nav is fixed.
@@ -717,7 +730,7 @@
   // Depending on whether the header is visible, set the side nav's height.
   if (headerVisible) {
     // The sidenav height grows as the header goes off screen
-    navHeight = windowHeight - (headerHeight + subheaderHeight - scrollTop) - topMargin;
+    navHeight = windowHeight - (headerHeight - scrollTop) - topMargin;
   } else {
     // Once header is off screen, the nav height is almost full window height
     navHeight = windowHeight - topMargin;
@@ -903,9 +916,111 @@
 /* #########     END COOKIES!     ########## */
 
 
+var sticky = false;
+var stickyTop;
+var prevScrollLeft = 0; // used to compare current position to previous position of horiz scroll
+/* Sets the vertical scoll position at which the sticky bar should appear.
+   This method is called to reset the position when search results appear or hide */
+function setStickyTop() {
+  stickyTop = $('#header-wrapper').outerHeight() - $('#sticky-header').outerHeight();
+}
 
+/*
+ * Displays sticky nav bar on pages when dac header scrolls out of view
+ */
+$(window).scroll(function(event) {
 
+  setStickyTop();
+  var hiding = false;
+  var $stickyEl = $('#sticky-header');
+  var $menuEl = $('.menu-container');
+  // Exit if there's no sidenav
+  if ($('#side-nav').length == 0) return;
+  // Exit if the mouse target is a DIV, because that means the event is coming
+  // from a scrollable div and so there's no need to make adjustments to our layout
+  if ($(event.target).nodeName == "DIV") {
+    return;
+  }
 
+  var top = $(window).scrollTop();
+  // we set the navbar fixed when the scroll position is beyond the height of the site header...
+  var shouldBeSticky = top >= stickyTop;
+  // ... except if the document content is shorter than the sidenav height.
+  // (this is necessary to avoid crazy behavior on OSX Lion due to overscroll bouncing)
+  if ($("#doc-col").height() < $("#side-nav").height()) {
+    shouldBeSticky = false;
+  }
+  // Account for horizontal scroll
+  var scrollLeft = $(window).scrollLeft();
+  // When the sidenav is fixed and user scrolls horizontally, reposition the sidenav to match
+  if (sticky && (scrollLeft != prevScrollLeft)) {
+    updateSideNavPosition();
+    prevScrollLeft = scrollLeft;
+  }
+
+  // Don't continue if the header is sufficently far away
+  // (to avoid intensive resizing that slows scrolling)
+  if (sticky == shouldBeSticky) {
+    return;
+  }
+
+  // If sticky header visible and position is now near top, hide sticky
+  if (sticky && !shouldBeSticky) {
+    sticky = false;
+    hiding = true;
+    // make the sidenav static again
+    $('#devdoc-nav')
+        .removeClass('fixed')
+        .css({'width':'auto','margin':''})
+        .prependTo('#side-nav');
+    // delay hide the sticky
+    $menuEl.removeClass('sticky-menu');
+    $stickyEl.fadeOut(250);
+    hiding = false;
+
+    // update the sidenaav position for side scrolling
+    updateSideNavPosition();
+  } else if (!sticky && shouldBeSticky) {
+    sticky = true;
+    $stickyEl.fadeIn(10);
+    $menuEl.addClass('sticky-menu');
+
+    // make the sidenav fixed
+    var width = $('#devdoc-nav').width();
+    $('#devdoc-nav')
+        .addClass('fixed')
+        .css({'width':width+'px'})
+        .prependTo('#body-content');
+
+    // update the sidenaav position for side scrolling
+    updateSideNavPosition();
+
+  } else if (hiding && top < 15) {
+    $menuEl.removeClass('sticky-menu');
+    $stickyEl.hide();
+    hiding = false;
+  }
+  resizeNav(250); // pass true in order to delay the scrollbar re-initialization for performance
+});
+
+/*
+ * Manages secion card states and nav resize to conclude loading
+ */
+(function() {
+  $(document).ready(function() {
+
+    // Stack hover states
+    $('.section-card-menu').each(function(index, el) {
+      var height = $(el).height();
+      $(el).css({height:height+'px', position:'relative'});
+      var $cardInfo = $(el).find('.card-info');
+
+      $cardInfo.css({position: 'absolute', bottom:'0px', left:'0px', right:'0px', overflow:'visible'});
+    });
+
+  });
+
+})();
 
 
 
@@ -972,8 +1087,16 @@
 }
 
 
+/* Call this to add listeners to a <select> element for Studio/Eclipse/Other docs */
+function setupIdeDocToggle() {
+  $( "select.ide" ).change(function() {
+    var selected = $(this).find("option:selected").attr("value");
+    $(".select-ide").hide();
+    $(".select-ide."+selected).show();
 
-
+    $("select.ide").val(selected);
+  });
+}
 
 
 
@@ -1519,8 +1642,8 @@
 
 function onSuggestionClick(link) {
   // When user clicks a suggested document, track it
-  _gaq.push(['_trackEvent', 'Suggestion Click', 'clicked: ' + $(link).text(),
-            'from: ' + $("#search_autocomplete").val()]);
+  ga('send', 'event', 'Suggestion Click', 'clicked: ' + $(link).text(),
+            'from: ' + $("#search_autocomplete").val());
 }
 
 function set_item_selected($li, selected)
@@ -1724,6 +1847,7 @@
             $('.suggest-card').hide();
             if ($("#searchResults").is(":hidden") && (search.value != "")) {
               // if results aren't showing (and text not empty), return true to allow search to execute
+              $('body,html').animate({scrollTop:0}, '500', 'swing');
               return true;
             } else {
               // otherwise, results are already showing, so allow ajax to auto refresh the results
@@ -1736,8 +1860,12 @@
             return false;
         }
     }
-    // Stop here if Google results are showing
+    // If Google results are showing, return true to allow ajax search to execute
     else if ($("#searchResults").is(":visible")) {
+        // Also, if search_results is scrolled out of view, scroll to top to make results visible
+        if ((sticky ) && (search.value != "")) {
+          $('body,html').animate({scrollTop:0}, '500', 'swing');
+        }
         return true;
     }
     // 38 UP ARROW
@@ -2278,13 +2406,13 @@
   var query = document.getElementById('search_autocomplete').value;
   location.hash = 'q=' + query;
   loadSearchResults();
-  $("#searchResults").slideDown('slow');
+  $("#searchResults").slideDown('slow', setStickyTop);
   return false;
 }
 
 
 function hideResults() {
-  $("#searchResults").slideUp();
+  $("#searchResults").slideUp('fast', setStickyTop);
   $(".search .close").addClass("hide");
   location.hash = '';
 
@@ -2401,27 +2529,44 @@
     return;
   } else {
     // first time loading search results for this page
-    $('#searchResults').slideDown('slow');
+    $('#searchResults').slideDown('slow', setStickyTop);
     $(".search .close").removeClass("hide");
     loadSearchResults();
   }
 }, true);
 
+/* Adjust the scroll position to account for sticky header, only if the hash matches an id.
+   This does not handle <a name=""> tags. Some CSS fixes those, but only for reference docs. */
+function offsetScrollForSticky() {
+  var hash = escape(location.hash.substr(1));
+  var $matchingElement = $("#"+hash);
+  // Sanity check that there's an element with that ID on the page
+  if ($matchingElement.length) {
+    // If the position of the target element is near the top of the page (<20px, where we expect it
+    // to be because we need to move it down 60px to become in view), then move it down 60px
+    if (Math.abs($matchingElement.offset().top - $(window).scrollTop()) < 20) {
+      $(window).scrollTop($(window).scrollTop() - 60);
+    }
+  }
+}
+
 // when an event on the browser history occurs (back, forward, load) requery hash and do search
 $(window).hashchange( function(){
-  // Exit if the hash isn't a search query or there's an error in the query
+  // If the hash isn't a search query or there's an error in the query,
+  // then adjust the scroll position to account for sticky header, then exit.
   if ((location.hash.indexOf("q=") == -1) || (query == "undefined")) {
     // If the results pane is open, close it.
     if (!$("#searchResults").is(":hidden")) {
       hideResults();
     }
+    offsetScrollForSticky();
     return;
   }
 
   // Otherwise, we have a search to do
   var query = decodeURI(getQuery(location.hash));
   searchControl.execute(query);
-  $('#searchResults').slideDown('slow');
+  $('#searchResults').slideDown('slow', setStickyTop);
   $("#search_autocomplete").focus();
   $(".search .close").removeClass("hide");
 
@@ -2465,8 +2610,8 @@
   $("#searchResults a.gs-title").each(function(index, link) {
     // When user clicks enter for Google search results, track it
     $(link).click(function() {
-      _gaq.push(['_trackEvent', 'Google Click', 'clicked: ' + $(this).text(),
-                'from: ' + $("#search_autocomplete").val()]);
+      ga('send', 'event', 'Google Click', 'clicked: ' + $(this).text(),
+                'from: ' + $("#search_autocomplete").val());
     });
   });
 }
@@ -2529,7 +2674,7 @@
   }
 
 function updateSidenavFixedWidth() {
-  if (!navBarIsFixed) return;
+  if (!sticky) return;
   $('#devdoc-nav').css({
     'width' : $('#side-nav').css('width'),
     'margin' : $('#side-nav').css('margin')
@@ -2540,7 +2685,7 @@
 }
 
 function updateSidenavFullscreenWidth() {
-  if (!navBarIsFixed) return;
+  if (!sticky) return;
   $('#devdoc-nav').css({
     'width' : $('#side-nav').css('width'),
     'margin' : $('#side-nav').css('margin')
@@ -3233,3 +3378,836 @@
   $("#samples").append($ul);
 
 }
+
+
+
+/* ########################################################## */
+/* ###################  RESOURCE CARDS  ##################### */
+/* ########################################################## */
+
+/** Handle resource queries, collections, and grids (sections). Requires
+    jd_tag_helpers.js and the *_unified_data.js to be loaded. */
+
+(function() {
+  // Prevent the same resource from being loaded more than once per page.
+  var addedPageResources = {};
+
+  $(document).ready(function() {
+    $('.resource-widget').each(function() {
+      initResourceWidget(this);
+    });
+
+    /* Pass the line height to ellipsisfade() to adjust the height of the
+    text container to show the max number of lines possible, without
+    showing lines that are cut off. This works with the css ellipsis
+    classes to fade last text line and apply an ellipsis char. */
+
+    //card text currently uses 15px line height.
+    var lineHeight = 15;
+    $('.card-info .text').ellipsisfade(lineHeight);
+  });
+
+  /*
+    Three types of resource layouts:
+    Flow - Uses a fixed row-height flow using float left style.
+    Carousel - Single card slideshow all same dimension absolute.
+    Stack - Uses fixed columns and flexible element height.
+  */
+  function initResourceWidget(widget) {
+    var $widget = $(widget);
+    var isFlow = $widget.hasClass('resource-flow-layout'),
+        isCarousel = $widget.hasClass('resource-carousel-layout'),
+        isStack = $widget.hasClass('resource-stack-layout');
+
+    // find size of widget by pulling out its class name
+    var sizeCols = 1;
+    var m = $widget.get(0).className.match(/\bcol-(\d+)\b/);
+    if (m) {
+      sizeCols = parseInt(m[1], 10);
+    }
+
+    var opts = {
+      cardSizes: ($widget.data('cardsizes') || '').split(','),
+      maxResults: parseInt($widget.data('maxresults') || '100', 10),
+      itemsPerPage: $widget.data('itemsperpage'),
+      sortOrder: $widget.data('sortorder'),
+      query: $widget.data('query'),
+      section: $widget.data('section'),
+      sizeCols: sizeCols,
+      /* Added by LFL 6/6/14 */
+      resourceStyle: $widget.data('resourcestyle') || 'card',
+      stackSort: $widget.data('stacksort') || 'true'
+    };
+
+    // run the search for the set of resources to show
+
+    var resources = buildResourceList(opts);
+
+    if (isFlow) {
+      drawResourcesFlowWidget($widget, opts, resources);
+    } else if (isCarousel) {
+      drawResourcesCarouselWidget($widget, opts, resources);
+    } else if (isStack) {
+      /* Looks like this got removed and is not used, so repurposing for the
+          homepage style layout.
+          Modified by LFL 6/6/14
+      */
+      //var sections = buildSectionList(opts);
+      opts['numStacks'] = $widget.data('numstacks');
+      drawResourcesStackWidget($widget, opts, resources/*, sections*/);
+    }
+  }
+
+  /* Initializes a Resource Carousel Widget */
+  function drawResourcesCarouselWidget($widget, opts, resources) {
+    $widget.empty();
+    var plusone = true; //always show plusone on carousel
+
+    $widget.addClass('resource-card slideshow-container')
+      .append($('<a>').addClass('slideshow-prev').text('Prev'))
+      .append($('<a>').addClass('slideshow-next').text('Next'));
+
+    var css = { 'width': $widget.width() + 'px',
+                'height': $widget.height() + 'px' };
+
+    var $ul = $('<ul>');
+
+    for (var i = 0; i < resources.length; ++i) {
+      var $card = $('<a>')
+        .attr('href', cleanUrl(resources[i].url))
+        .decorateResourceCard(resources[i],plusone);
+
+      $('<li>').css(css)
+          .append($card)
+          .appendTo($ul);
+    }
+
+    $('<div>').addClass('frame')
+      .append($ul)
+      .appendTo($widget);
+
+    $widget.dacSlideshow({
+      auto: true,
+      btnPrev: '.slideshow-prev',
+      btnNext: '.slideshow-next'
+    });
+  };
+
+  /* Initializes a Resource Card Stack Widget (column-based layout)
+     Modified by LFL 6/6/14
+   */
+  function drawResourcesStackWidget($widget, opts, resources, sections) {
+    // Don't empty widget, grab all items inside since they will be the first
+    // items stacked, followed by the resource query
+    var plusone = true; //by default show plusone on section cards
+    var cards = $widget.find('.resource-card').detach().toArray();
+    var numStacks = opts.numStacks || 1;
+    var $stacks = [];
+    var urlString;
+
+    for (var i = 0; i < numStacks; ++i) {
+      $stacks[i] = $('<div>').addClass('resource-card-stack')
+          .appendTo($widget);
+    }
+
+    var sectionResources = [];
+
+    // Extract any subsections that are actually resource cards
+    if (sections) {
+      for (var i = 0; i < sections.length; ++i) {
+        if (!sections[i].sections || !sections[i].sections.length) {
+          // Render it as a resource card
+          sectionResources.push(
+            $('<a>')
+              .addClass('resource-card section-card')
+              .attr('href', cleanUrl(sections[i].resource.url))
+              .decorateResourceCard(sections[i].resource,plusone)[0]
+          );
+
+        } else {
+          cards.push(
+            $('<div>')
+              .addClass('resource-card section-card-menu')
+              .decorateResourceSection(sections[i],plusone)[0]
+          );
+        }
+      }
+    }
+
+    cards = cards.concat(sectionResources);
+
+    for (var i = 0; i < resources.length; ++i) {
+      var $card = createResourceElement(resources[i], opts);
+
+      if (opts.resourceStyle.indexOf('related') > -1) {
+        $card.addClass('related-card');
+      }
+
+      cards.push($card[0]);
+    }
+
+    if (opts.stackSort != 'false') {
+      for (var i = 0; i < cards.length; ++i) {
+        // Find the stack with the shortest height, but give preference to
+        // left to right order.
+        var minHeight = $stacks[0].height();
+        var minIndex = 0;
+
+        for (var j = 1; j < numStacks; ++j) {
+          var height = $stacks[j].height();
+          if (height < minHeight - 45) {
+            minHeight = height;
+            minIndex = j;
+          }
+        }
+
+        $stacks[minIndex].append($(cards[i]));
+      }
+    }
+
+  };
+
+  /*
+    Create a resource card using the given resource object and a list of html
+     configured options. Returns a jquery object containing the element.
+  */
+  function createResourceElement(resource, opts, plusone) {
+    var $el;
+
+    // The difference here is that generic cards are not entirely clickable
+    // so its a div instead of an a tag, also the generic one is not given
+    // the resource-card class so it appears with a transparent background
+    // and can be styled in whatever way the css setup.
+    if (opts.resourceStyle == 'generic') {
+      $el = $('<div>')
+        .addClass('resource')
+        .attr('href', cleanUrl(resource.url))
+        .decorateResource(resource, opts);
+    } else {
+      var cls = 'resource resource-card';
+
+      $el = $('<a>')
+        .addClass(cls)
+        .attr('href', cleanUrl(resource.url))
+        .decorateResourceCard(resource, plusone);
+    }
+
+    return $el;
+  }
+
+  /* Initializes a flow widget, see distribute.scss for generating accompanying css */
+  function drawResourcesFlowWidget($widget, opts, resources) {
+    $widget.empty();
+    var cardSizes = opts.cardSizes || ['6x6'];
+    var i = 0, j = 0;
+    var plusone = true; // by default show plusone on resource cards
+
+    while (i < resources.length) {
+      var cardSize = cardSizes[j++ % cardSizes.length];
+      cardSize = cardSize.replace(/^\s+|\s+$/,'');
+      // Some card sizes do not get a plusone button, such as where space is constrained
+      // or for cards commonly embedded in docs (to improve overall page speed).
+      plusone = !((cardSize == "6x2") || (cardSize == "6x3") ||
+                  (cardSize == "9x2") || (cardSize == "9x3") ||
+                  (cardSize == "12x2") || (cardSize == "12x3"));
+
+      // A stack has a third dimension which is the number of stacked items
+      var isStack = cardSize.match(/(\d+)x(\d+)x(\d+)/);
+      var stackCount = 0;
+      var $stackDiv = null;
+
+      if (isStack) {
+        // Create a stack container which should have the dimensions defined
+        // by the product of the items inside.
+        $stackDiv = $('<div>').addClass('resource-card-stack resource-card-' + isStack[1]
+            + 'x' + isStack[2] * isStack[3]) .appendTo($widget);
+      }
+
+      // Build each stack item or just a single item
+      do {
+        var resource = resources[i];
+
+        var $card = createResourceElement(resources[i], opts, plusone);
+
+        $card.addClass('resource-card-' + cardSize +
+          ' resource-card-' + resource.type);
+
+        if (isStack) {
+          $card.addClass('resource-card-' + isStack[1] + 'x' + isStack[2]);
+          if (++stackCount == parseInt(isStack[3])) {
+            $card.addClass('resource-card-row-stack-last');
+            stackCount = 0;
+          }
+        } else {
+          stackCount = 0;
+        }
+
+        $card.appendTo($stackDiv || $widget);
+
+      } while (++i < resources.length && stackCount > 0);
+    }
+  }
+
+  /* Build a site map of resources using a section as a root. */
+  function buildSectionList(opts) {
+    if (opts.section && SECTION_BY_ID[opts.section]) {
+      return SECTION_BY_ID[opts.section].sections || [];
+    }
+    return [];
+  }
+
+  function buildResourceList(opts) {
+    var maxResults = opts.maxResults || 100;
+
+    var query = opts.query || '';
+    var expressions = parseResourceQuery(query);
+    var addedResourceIndices = {};
+    var results = [];
+
+    for (var i = 0; i < expressions.length; i++) {
+      var clauses = expressions[i];
+
+      // build initial set of resources from first clause
+      var firstClause = clauses[0];
+      var resources = [];
+      switch (firstClause.attr) {
+        case 'type':
+          resources = ALL_RESOURCES_BY_TYPE[firstClause.value];
+          break;
+        case 'lang':
+          resources = ALL_RESOURCES_BY_LANG[firstClause.value];
+          break;
+        case 'tag':
+          resources = ALL_RESOURCES_BY_TAG[firstClause.value];
+          break;
+        case 'collection':
+          var urls = RESOURCE_COLLECTIONS[firstClause.value].resources || [];
+          resources = urls.map(function(url){ return ALL_RESOURCES_BY_URL[url]; });
+          break;
+        case 'section':
+          var urls = SITE_MAP[firstClause.value].sections || [];
+          resources = urls.map(function(url){ return ALL_RESOURCES_BY_URL[url]; });
+          break;
+      }
+      // console.log(firstClause.attr + ':' + firstClause.value);
+      resources = resources || [];
+
+      // use additional clauses to filter corpus
+      if (clauses.length > 1) {
+        var otherClauses = clauses.slice(1);
+        resources = resources.filter(getResourceMatchesClausesFilter(otherClauses));
+      }
+
+      // filter out resources already added
+      if (i > 1) {
+        resources = resources.filter(getResourceNotAlreadyAddedFilter(addedResourceIndices));
+      }
+
+      // add to list of already added indices
+      for (var j = 0; j < resources.length; j++) {
+        // console.log(resources[j].title);
+        addedResourceIndices[resources[j].index] = 1;
+      }
+
+      // concat to final results list
+      results = results.concat(resources);
+    }
+
+    if (opts.sortOrder && results.length) {
+      var attr = opts.sortOrder;
+
+      if (opts.sortOrder == 'random') {
+        var i = results.length, j, temp;
+        while (--i) {
+          j = Math.floor(Math.random() * (i + 1));
+          temp = results[i];
+          results[i] = results[j];
+          results[j] = temp;
+        }
+      } else {
+        var desc = attr.charAt(0) == '-';
+        if (desc) {
+          attr = attr.substring(1);
+        }
+        results = results.sort(function(x,y) {
+          return (desc ? -1 : 1) * (parseInt(x[attr], 10) - parseInt(y[attr], 10));
+        });
+      }
+    }
+
+    results = results.filter(getResourceNotAlreadyAddedFilter(addedPageResources));
+    results = results.slice(0, maxResults);
+
+    for (var j = 0; j < results.length; ++j) {
+      addedPageResources[results[j].index] = 1;
+    }
+
+    return results;
+  }
+
+
+  function getResourceNotAlreadyAddedFilter(addedResourceIndices) {
+    return function(resource) {
+      return !addedResourceIndices[resource.index];
+    };
+  }
+
+
+  function getResourceMatchesClausesFilter(clauses) {
+    return function(resource) {
+      return doesResourceMatchClauses(resource, clauses);
+    };
+  }
+
+
+  function doesResourceMatchClauses(resource, clauses) {
+    for (var i = 0; i < clauses.length; i++) {
+      var map;
+      switch (clauses[i].attr) {
+        case 'type':
+          map = IS_RESOURCE_OF_TYPE[clauses[i].value];
+          break;
+        case 'lang':
+          map = IS_RESOURCE_IN_LANG[clauses[i].value];
+          break;
+        case 'tag':
+          map = IS_RESOURCE_TAGGED[clauses[i].value];
+          break;
+      }
+
+      if (!map || (!!clauses[i].negative ? map[resource.index] : !map[resource.index])) {
+        return clauses[i].negative;
+      }
+    }
+    return true;
+  }
+
+  function cleanUrl(url)
+  {
+    if (url && url.indexOf('//') === -1) {
+      url = toRoot + url;
+    }
+
+    return url;
+  }
+
+
+  function parseResourceQuery(query) {
+    // Parse query into array of expressions (expression e.g. 'tag:foo + type:video')
+    var expressions = [];
+    var expressionStrs = query.split(',') || [];
+    for (var i = 0; i < expressionStrs.length; i++) {
+      var expr = expressionStrs[i] || '';
+
+      // Break expression into clauses (clause e.g. 'tag:foo')
+      var clauses = [];
+      var clauseStrs = expr.split(/(?=[\+\-])/);
+      for (var j = 0; j < clauseStrs.length; j++) {
+        var clauseStr = clauseStrs[j] || '';
+
+        // Get attribute and value from clause (e.g. attribute='tag', value='foo')
+        var parts = clauseStr.split(':');
+        var clause = {};
+
+        clause.attr = parts[0].replace(/^\s+|\s+$/g,'');
+        if (clause.attr) {
+          if (clause.attr.charAt(0) == '+') {
+            clause.attr = clause.attr.substring(1);
+          } else if (clause.attr.charAt(0) == '-') {
+            clause.negative = true;
+            clause.attr = clause.attr.substring(1);
+          }
+        }
+
+        if (parts.length > 1) {
+          clause.value = parts[1].replace(/^\s+|\s+$/g,'');
+        }
+
+        clauses.push(clause);
+      }
+
+      if (!clauses.length) {
+        continue;
+      }
+
+      expressions.push(clauses);
+    }
+
+    return expressions;
+  }
+})();
+
+(function($) {
+
+  /*
+    Utility method for creating dom for the description area of a card.
+    Used in decorateResourceCard and decorateResource.
+  */
+  function buildResourceCardDescription(resource, plusone) {
+    var $description = $('<div>').addClass('description ellipsis');
+
+    $description.append($('<div>').addClass('text').html(resource.summary));
+
+    if (resource.cta) {
+      $description.append($('<a>').addClass('cta').html(resource.cta));
+    }
+
+    if (plusone) {
+      var plusurl = resource.url.indexOf("//") > -1 ? resource.url :
+        "//developer.android.com/" + resource.url;
+
+      $description.append($('<div>').addClass('util')
+        .append($('<div>').addClass('g-plusone')
+          .attr('data-size', 'small')
+          .attr('data-align', 'right')
+          .attr('data-href', plusurl)));
+    }
+
+    return $description;
+  }
+
+
+  /* Simple jquery function to create dom for a standard resource card */
+  $.fn.decorateResourceCard = function(resource,plusone) {
+    var section = resource.group || resource.type;
+    var imgUrl = resource.image ||
+      'assets/images/resource-card-default-android.jpg';
+
+    if (imgUrl.indexOf('//') === -1) {
+      imgUrl = toRoot + imgUrl;
+    }
+
+    $('<div>').addClass('card-bg')
+      .css('background-image', 'url(' + (imgUrl || toRoot +
+        'assets/images/resource-card-default-android.jpg') + ')')
+      .appendTo(this);
+
+    $('<div>').addClass('card-info' + (!resource.summary ? ' empty-desc' : ''))
+      .append($('<div>').addClass('section').text(section))
+      .append($('<div>').addClass('title').html(resource.title))
+      .append(buildResourceCardDescription(resource, plusone))
+      .appendTo(this);
+
+    return this;
+  };
+
+  /* Simple jquery function to create dom for a resource section card (menu) */
+  $.fn.decorateResourceSection = function(section,plusone) {
+    var resource = section.resource;
+    //keep url clean for matching and offline mode handling
+    var urlPrefix = resource.image.indexOf("//") > -1 ? "" : toRoot;
+    var $base = $('<a>')
+        .addClass('card-bg')
+        .attr('href', resource.url)
+        .append($('<div>').addClass('card-section-icon')
+          .append($('<div>').addClass('icon'))
+          .append($('<div>').addClass('section').html(resource.title)))
+      .appendTo(this);
+
+    var $cardInfo = $('<div>').addClass('card-info').appendTo(this);
+
+    if (section.sections && section.sections.length) {
+      // Recurse the section sub-tree to find a resource image.
+      var stack = [section];
+
+      while (stack.length) {
+        if (stack[0].resource.image) {
+          $base.css('background-image', 'url(' + urlPrefix + stack[0].resource.image + ')');
+          break;
+        }
+
+        if (stack[0].sections) {
+          stack = stack.concat(stack[0].sections);
+        }
+
+        stack.shift();
+      }
+
+      var $ul = $('<ul>')
+        .appendTo($cardInfo);
+
+      var max = section.sections.length > 3 ? 3 : section.sections.length;
+
+      for (var i = 0; i < max; ++i) {
+
+        var subResource = section.sections[i];
+        if (!plusone) {
+          $('<li>')
+            .append($('<a>').attr('href', subResource.url)
+              .append($('<div>').addClass('title').html(subResource.title))
+              .append($('<div>').addClass('description ellipsis')
+                .append($('<div>').addClass('text').html(subResource.summary))
+                .append($('<div>').addClass('util'))))
+          .appendTo($ul);
+        } else {
+          $('<li>')
+            .append($('<a>').attr('href', subResource.url)
+              .append($('<div>').addClass('title').html(subResource.title))
+              .append($('<div>').addClass('description ellipsis')
+                .append($('<div>').addClass('text').html(subResource.summary))
+                .append($('<div>').addClass('util')
+                  .append($('<div>').addClass('g-plusone')
+                    .attr('data-size', 'small')
+                    .attr('data-align', 'right')
+                    .attr('data-href', resource.url)))))
+          .appendTo($ul);
+        }
+      }
+
+      // Add a more row
+      if (max < section.sections.length) {
+        $('<li>')
+          .append($('<a>').attr('href', resource.url)
+            .append($('<div>')
+              .addClass('title')
+              .text('More')))
+        .appendTo($ul);
+      }
+    } else {
+      // No sub-resources, just render description?
+    }
+
+    return this;
+  };
+
+
+
+
+  /* Render other types of resource styles that are not cards. */
+  $.fn.decorateResource = function(resource, opts) {
+    var imgUrl = resource.image ||
+      'assets/images/resource-card-default-android.jpg';
+    var linkUrl = resource.url;
+
+    if (imgUrl.indexOf('//') === -1) {
+      imgUrl = toRoot + imgUrl;
+    }
+
+    if (linkUrl && linkUrl.indexOf('//') === -1) {
+      linkUrl = toRoot + linkUrl;
+    }
+
+    $(this).append(
+      $('<div>').addClass('image')
+        .css('background-image', 'url(' + imgUrl + ')'),
+      $('<div>').addClass('info').append(
+        $('<h4>').addClass('title').html(resource.title),
+        $('<p>').addClass('summary').html(resource.summary),
+        $('<a>').attr('href', linkUrl).addClass('cta').html('Learn More')
+      )
+    );
+
+    return this;
+  };
+})(jQuery);
+
+
+/* Calculate the vertical area remaining */
+(function($) {
+    $.fn.ellipsisfade= function(lineHeight) {
+        this.each(function() {
+            // get element text
+            var $this = $(this);
+            var remainingHeight = $this.parent().parent().height();
+            $this.parent().siblings().each(function ()
+            {
+              if ($(this).is(":visible")) {
+                var h = $(this).height();
+                remainingHeight = remainingHeight - h;
+              }
+            });
+
+            adjustedRemainingHeight = ((remainingHeight)/lineHeight>>0)*lineHeight
+            $this.parent().css({'height': adjustedRemainingHeight});
+            $this.css({'height': "auto"});
+        });
+
+        return this;
+    };
+}) (jQuery);
+
+/*
+  Fullscreen Carousel
+
+  The following allows for an area at the top of the page that takes over the
+  entire browser height except for its top offset and an optional bottom
+  padding specified as a data attribute.
+
+  HTML:
+
+  <div class="fullscreen-carousel">
+    <div class="fullscreen-carousel-content">
+      <!-- content here -->
+    </div>
+    <div class="fullscreen-carousel-content">
+      <!-- content here -->
+    </div>
+
+    etc ...
+
+  </div>
+
+  Control over how the carousel takes over the screen can mostly be defined in
+  a css file. Setting min-height on the .fullscreen-carousel-content elements
+  will prevent them from shrinking to far vertically when the browser is very
+  short, and setting max-height on the .fullscreen-carousel itself will prevent
+  the area from becoming to long in the case that the browser is stretched very
+  tall.
+
+  There is limited functionality for having multiple sections since that request
+  was removed, but it is possible to add .next-arrow and .prev-arrow elements to
+  scroll between multiple content areas.
+*/
+
+(function() {
+  $(document).ready(function() {
+    $('.fullscreen-carousel').each(function() {
+      initWidget(this);
+    });
+  });
+
+  function initWidget(widget) {
+    var $widget = $(widget);
+
+    var topOffset = $widget.offset().top;
+    var padBottom = parseInt($widget.data('paddingbottom')) || 0;
+    var maxHeight = 0;
+    var minHeight = 0;
+    var $content = $widget.find('.fullscreen-carousel-content');
+    var $nextArrow = $widget.find('.next-arrow');
+    var $prevArrow = $widget.find('.prev-arrow');
+    var $curSection = $($content[0]);
+
+    if ($content.length <= 1) {
+      $nextArrow.hide();
+      $prevArrow.hide();
+    } else {
+      $nextArrow.click(function() {
+        var index = ($content.index($curSection) + 1);
+        $curSection.hide();
+        $curSection = $($content[index >= $content.length ? 0 : index]);
+        $curSection.show();
+      });
+
+      $prevArrow.click(function() {
+        var index = ($content.index($curSection) - 1);
+        $curSection.hide();
+        $curSection = $($content[index < 0 ? $content.length - 1 : 0]);
+        $curSection.show();
+      });
+    }
+
+    // Just hide all content sections except first.
+    $content.each(function(index) {
+      if ($(this).height() > minHeight) minHeight = $(this).height();
+      $(this).css({position: 'absolute',  display: index > 0 ? 'none' : ''});
+    });
+
+    // Register for changes to window size, and trigger.
+    $(window).resize(resizeWidget);
+    resizeWidget();
+
+    function resizeWidget() {
+      var height = $(window).height() - topOffset - padBottom;
+      $widget.width($(window).width());
+      $widget.height(height < minHeight ? minHeight :
+        (maxHeight && height > maxHeight ? maxHeight : height));
+    }
+  }
+})();
+
+
+
+
+
+/*
+  Tab Carousel
+
+  The following allows tab widgets to be installed via the html below. Each
+  tab content section should have a data-tab attribute matching one of the
+  nav items'. Also each tab content section should have a width matching the
+  tab carousel.
+
+  HTML:
+
+  <div class="tab-carousel">
+    <ul class="tab-nav">
+      <li><a href="#" data-tab="handsets">Handsets</a>
+      <li><a href="#" data-tab="wearable">Wearable</a>
+      <li><a href="#" data-tab="tv">TV</a>
+    </ul>
+
+    <div class="tab-carousel-content">
+      <div data-tab="handsets">
+        <!--Full width content here-->
+      </div>
+
+      <div data-tab="wearable">
+        <!--Full width content here-->
+      </div>
+
+      <div data-tab="tv">
+        <!--Full width content here-->
+      </div>
+    </div>
+  </div>
+
+*/
+(function() {
+  $(document).ready(function() {
+    $('.tab-carousel').each(function() {
+      initWidget(this);
+    });
+  });
+
+  function initWidget(widget) {
+    var $widget = $(widget);
+    var $nav = $widget.find('.tab-nav');
+    var $anchors = $nav.find('[data-tab]');
+    var $li = $nav.find('li');
+    var $contentContainer = $widget.find('.tab-carousel-content');
+    var $tabs = $contentContainer.find('[data-tab]');
+    var $curTab = $($tabs[0]); // Current tab is first tab.
+    var width = $widget.width();
+
+    // Setup nav interactivity.
+    $anchors.click(function(evt) {
+      evt.preventDefault();
+      var query = '[data-tab=' + $(this).data('tab') + ']';
+      transitionWidget($tabs.filter(query));
+    });
+
+    // Add highlight for navigation on first item.
+    var $highlight = $('<div>').addClass('highlight')
+      .css({left:$li.position().left + 'px', width:$li.outerWidth() + 'px'})
+      .appendTo($nav);
+
+    // Store height since we will change contents to absolute.
+    $contentContainer.height($contentContainer.height());
+
+    // Absolutely position tabs so they're ready for transition.
+    $tabs.each(function(index) {
+      $(this).css({position: 'absolute', left: index > 0 ? width + 'px' : '0'});
+    });
+
+    function transitionWidget($toTab) {
+      if (!$curTab.is($toTab)) {
+        var curIndex = $tabs.index($curTab[0]);
+        var toIndex = $tabs.index($toTab[0]);
+        var dir = toIndex > curIndex ? 1 : -1;
+
+        // Animate content sections.
+        $toTab.css({left:(width * dir) + 'px'});
+        $curTab.animate({left:(width * -dir) + 'px'});
+        $toTab.animate({left:'0'});
+
+        // Animate navigation highlight.
+        $highlight.animate({left:$($li[toIndex]).position().left + 'px',
+          width:$($li[toIndex]).outerWidth() + 'px'})
+
+        // Store new current section.
+        $curTab = $toTab;
+      }
+    }
+  }
+})();
\ No newline at end of file
diff --git a/tools/droiddoc/templates-sdk/class.cs b/tools/droiddoc/templates-sdk/class.cs
index 0461af6..7aa99f9 100644
--- a/tools/droiddoc/templates-sdk/class.cs
+++ b/tools/droiddoc/templates-sdk/class.cs
@@ -1,9 +1,12 @@
 <?cs include:"doctype.cs" ?>
 <?cs include:"macros.cs" ?>
+<?cs include:"macros_override.cs" ?>
 <html<?cs if:devsite ?> devsite<?cs /if ?>>
 <?cs include:"head_tag.cs" ?>
 <body class="gc-documentation <?cs if:(reference.gms || reference.gcm) ?>google<?cs /if ?>
   <?cs if:(guide||develop||training||reference||tools||sdk) ?>develop<?cs
+    if:reference ?> reference<?cs
+    /if ?><?cs
   elif:design ?>design<?cs
   elif:distribute ?>distribute<?cs
   /if ?>" itemscope itemtype="http://schema.org/Article">
@@ -123,6 +126,7 @@
   <?cs /if ?>
   <?cs set:colspan = colspan-1 ?>
 <?cs /each ?>
+<?cs call:show_annotations_list(class) ?>
 
 </div><!-- end header -->
 
@@ -193,7 +197,10 @@
         <td class="jd-linkcol" width="100%"><nobr>
         <span class="sympad"><?cs call:cond_link(method.name, toroot, method.href, included) ?></span>(<?cs call:parameter_list(method.params) ?>)</nobr>
         <?cs if:subcount(method.shortDescr) || subcount(method.deprecated) ?>
-        <div class="jd-descrdiv"><?cs call:short_descr(method) ?></div>
+        <div class="jd-descrdiv">
+          <?cs call:short_descr(method) ?>
+          <?cs call:show_annotations_list(method) ?>
+        </div>
   <?cs /if ?>
   </td></tr>
 <?cs set:count = count + #1 ?>
@@ -210,7 +217,10 @@
           <?cs var:field.final ?>
           <?cs call:type_link(field.type) ?></nobr></td>
           <td class="jd-linkcol"><?cs call:cond_link(field.name, toroot, field.href, included) ?></td>
-          <td class="jd-descrcol" width="100%"><?cs call:short_descr(field) ?></td>
+          <td class="jd-descrcol" width="100%">
+            <?cs call:short_descr(field) ?>
+            <?cs call:show_annotations_list(field) ?>
+          </td>
       </tr>
       <?cs set:count = count + #1 ?>
     <?cs /each ?>
@@ -222,7 +232,10 @@
     <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:field.since ?>" >
         <td class="jd-typecol"><?cs call:type_link(field.type) ?></td>
         <td class="jd-linkcol"><?cs call:cond_link(field.name, toroot, field.href, included) ?></td>
-        <td class="jd-descrcol" width="100%"><?cs call:short_descr(field) ?></td>
+        <td class="jd-descrcol" width="100%">
+          <?cs call:short_descr(field) ?>
+          <?cs call:show_annotations_list(field) ?>
+        </td>
     </tr>
     <?cs set:count = count + #1 ?>
     <?cs /each ?>
@@ -242,7 +255,10 @@
             <?cs call:cond_link(m.name, toroot, m.href, included) ?>
             <?cs /each ?>
         </td>
-        <td class="jd-descrcol" width="100%"><?cs call:short_descr(attr) ?>&nbsp;</td>
+        <td class="jd-descrcol" width="100%">
+          <?cs call:short_descr(attr) ?>&nbsp;
+          <?cs call:show_annotations_list(attr) ?>
+        </td>
     </tr>
     <?cs set:count = count + #1 ?>
     <?cs /each ?>
@@ -259,7 +275,10 @@
         <?cs var:cl.abstract ?>
         <?cs var:cl.kind ?></nobr></td>
       <td class="jd-linkcol"><?cs call:type_link(cl.type) ?></td>
-      <td class="jd-descrcol" width="100%"><?cs call:short_descr(cl) ?>&nbsp;</td>
+      <td class="jd-descrcol" width="100%">
+        <?cs call:short_descr(cl) ?>&nbsp;
+        <?cs call:show_annotations_list(cl) ?>
+      </td>
     </tr>
     <?cs set:count = count + #1 ?>
     <?cs /each ?>
@@ -335,7 +354,10 @@
     <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:field.since ?>" >
         <td class="jd-descrcol"><?cs call:type_link(field.type) ?>&nbsp;</td>
         <td class="jd-linkcol"><?cs call:cond_link(field.name, toroot, field.href, cl.included) ?>&nbsp;</td>
-        <td class="jd-descrcol" width="100%"><?cs call:short_descr(field) ?>&nbsp;</td>
+        <td class="jd-descrcol" width="100%">
+          <?cs call:short_descr(field) ?>&nbsp;
+          <?cs call:show_annotations_list(field) ?>
+        </td>
     </tr>
     <?cs set:count = count + #1 ?>
     <?cs /each ?>
@@ -504,6 +526,7 @@
         <?cs call:federated_refs(field) ?>
       </div>
     <div class="jd-details-descr">
+      <?cs call:show_annotations_list(field) ?>
       <?cs call:description(field) ?>
     <?cs if:subcount(field.constantValue) ?>
         <div class="jd-tagdata">
@@ -546,6 +569,7 @@
         <?cs call:federated_refs(method) ?>
       </div>
     <div class="jd-details-descr">
+      <?cs call:show_annotations_list(method) ?>
       <?cs call:description(method) ?>
     </div>
 </div>
@@ -560,6 +584,7 @@
     <h4 class="jd-details-title"><?cs var:attr.name ?>
     </h4>
     <div class="jd-details-descr">
+        <?cs call:show_annotations_list(attr) ?>
         <?cs call:description(attr) ?>
 
         <div class="jd-tagdata">
diff --git a/tools/droiddoc/templates-sdk/classes.cs b/tools/droiddoc/templates-sdk/classes.cs
index 6769f47..405892d 100644
--- a/tools/droiddoc/templates-sdk/classes.cs
+++ b/tools/droiddoc/templates-sdk/classes.cs
@@ -1,9 +1,12 @@
 <?cs include:"doctype.cs" ?>
 <?cs include:"macros.cs" ?>
+<?cs include:"macros_override.cs" ?>
 <html<?cs if:devsite ?> devsite<?cs /if ?>>
 <?cs include:"head_tag.cs" ?>
 <body class="gc-documentation <?cs if:(reference.gms || reference.gcm) ?>google<?cs /if ?>
   <?cs if:(guide||develop||training||reference||tools||sdk) ?>develop<?cs
+    if:reference ?> reference<?cs
+    /if ?><?cs
   elif:design ?>design<?cs
   elif:distribute ?>distribute<?cs
   /if ?>" itemscope itemtype="http://schema.org/Article">
@@ -30,7 +33,10 @@
     <?cs each:cl = letter ?>
         <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:cl.since ?>" >
             <td class="jd-linkcol"><?cs call:type_link(cl.type) ?></td>
-            <td class="jd-descrcol" width="100%"><?cs call:short_descr(cl) ?>&nbsp;</td>
+            <td class="jd-descrcol" width="100%">
+              <?cs call:short_descr(cl) ?>&nbsp;
+              <?cs call:show_annotations_list(cl) ?>
+            </td>
         </tr>
     <?cs set:count = count + #1 ?>
     <?cs /each ?>
diff --git a/tools/droiddoc/templates-sdk/components/masthead.cs b/tools/droiddoc/templates-sdk/components/masthead.cs
index 47639bb..c880eee 100644
--- a/tools/droiddoc/templates-sdk/components/masthead.cs
+++ b/tools/droiddoc/templates-sdk/components/masthead.cs
@@ -1,226 +1,160 @@
 <?cs def:custom_masthead() ?>
+<?cs if:preview ?>
+  <?cs call:preview_masthead() ?>
+<?cs else ?>
 <a name="top"></a>
-<?cs if:!devsite ?><?cs # leave out the global header for devsite; it's in devsite template ?>
-    <!-- Header -->
+<?cs if:!devsite ?><?cs # leave out the global header for devsite; it is in devsite template ?>
+  <!-- Header -->
+  <div id="header-wrapper">
     <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo">
+      <div class="wrap" id="header-wrap">
+        <div class="col-3 logo">
           <a href="<?cs var:toroot ?>index.html">
-            <img src="<?cs var:toroot ?>assets/images/dac_logo.png" width="123" height="25" alt="Android Developers" />
+            <img src="<?cs var:toroot ?>assets/images/dac_logo.png"
+                srcset="<?cs var:toroot ?>assets/images/dac_logo@2x.png 2x"
+                width="123" height="25" alt="Android Developers" />
           </a>
           <div class="btn-quicknav" id="btn-quicknav">
-          	<a href="#" class="arrow-inactive">Quicknav</a>
-			      <a href="#" class="arrow-active">Quicknav</a>
+            <a href="#" class="arrow-inactive">Quicknav</a>
+            <a href="#" class="arrow-active">Quicknav</a>
           </div>
-          </div>
-            <ul class="nav-x col-9">
-                <li class="design">
-                  <a href="<?cs var:toroot ?>design/index.html"
-                  zh-tw-lang="設計"
-                  zh-cn-lang="设计"
-                  ru-lang="Проектирование"
-                  ko-lang="디자인"
-                  ja-lang="設計"
-                  es-lang="Diseñar"               
-                  >Design</a></li>
-                <li class="develop"><a href="<?cs var:toroot ?>develop/index.html"
-                  zh-tw-lang="開發"
-                  zh-cn-lang="开发"
-                  ru-lang="Разработка"
-                  ko-lang="개발"
-                  ja-lang="開発"
-                  es-lang="Desarrollar"               
-                  >Develop</a></li>
-                <li class="distribute last"><a href="<?cs var:toroot ?>distribute/index.html"
-                  zh-tw-lang="發佈"
-                  zh-cn-lang="分发"
-                  ru-lang="Распространение"
-                  ko-lang="배포"
-                  ja-lang="配布"
-                  es-lang="Distribuir"               
-                  >Distribute</a></li>
+        </div>
+        <ul class="nav-x col-9">
+            <li class="design">
+              <a href="<?cs var:toroot ?>design/index.html"
+              zh-tw-lang="設計"
+              zh-cn-lang="设计"
+              ru-lang="Проектирование"
+              ko-lang="디자인"
+              ja-lang="設計"
+              es-lang="Diseñar"
+              >Design</a></li>
+            <li class="develop"><a href="<?cs var:toroot ?>develop/index.html"
+              zh-tw-lang="開發"
+              zh-cn-lang="开发"
+              ru-lang="Разработка"
+              ko-lang="개발"
+              ja-lang="開発"
+              es-lang="Desarrollar"
+              >Develop</a></li>
+            <li class="distribute last"><a href="<?cs var:toroot ?>distribute/<?cs
+              if:android.whichdoc == "offline" ?>googleplay/<?cs /if ?>index.html"
+              zh-tw-lang="發佈"
+              zh-cn-lang="分发"
+              ru-lang="Распространение"
+              ko-lang="배포"
+              ja-lang="配布"
+              es-lang="Distribuir"
+              >Distribute</a></li>
+        </ul>
+
+
+        <?cs # ADD SEARCH AND MENU ?>
+        <?cs call:header_search_widget() ?>
+
+
+        <!-- Expanded quicknav -->
+        <div id="quicknav" class="col-13">
+          <ul>
+            <li class="about">
+              <ul>
+                <li><a href="<?cs var:toroot ?>about/index.html">About</a></li>
+                <li><a href="<?cs var:toroot ?>wear/index.html">Wear</a></li>
+                <li><a href="<?cs var:toroot ?>tv/index.html">TV</a></li>
+                <li><a href="<?cs var:toroot ?>auto/index.html">Auto</a></li>
+              </ul>
+            </li>
+            <li class="design">
+              <ul>
+                <li><a href="<?cs var:toroot ?>design/index.html">Get Started</a></li>
+                <li><a href="<?cs var:toroot ?>design/devices.html">Devices</a></li>
+                <li><a href="<?cs var:toroot ?>design/style/index.html">Style</a></li>
+                <li><a href="<?cs var:toroot ?>design/patterns/index.html">Patterns</a></li>
+                <li><a href="<?cs var:toroot ?>design/building-blocks/index.html">Building Blocks</a></li>
+                <li><a href="<?cs var:toroot ?>design/downloads/index.html">Downloads</a></li>
+                <li><a href="<?cs var:toroot ?>design/videos/index.html">Videos</a></li>
+              </ul>
+            </li>
+            <li class="develop">
+              <ul>
+                <li><a href="<?cs var:toroot ?>training/index.html"
+                  zh-tw-lang="訓練課程"
+                  zh-cn-lang="培训"
+                  ru-lang="Курсы"
+                  ko-lang="교육"
+                  ja-lang="トレーニング"
+                  es-lang="Capacitación"
+                  >Training</a></li>
+                <li><a href="<?cs var:toroot ?>guide/index.html"
+                  zh-tw-lang="API 指南"
+                  zh-cn-lang="API 指南"
+                  ru-lang="Руководства по API"
+                  ko-lang="API 가이드"
+                  ja-lang="API ガイド"
+                  es-lang="Guías de la API"
+                  >API Guides</a></li>
+                <li><a href="<?cs var:toroot ?>reference/packages.html"
+                  zh-tw-lang="參考資源"
+                  zh-cn-lang="参考"
+                  ru-lang="Справочник"
+                  ko-lang="참조문서"
+                  ja-lang="リファレンス"
+                  es-lang="Referencia"
+                  >Reference</a></li>
+                <li><a href="<?cs var:toroot ?>sdk/index.html"
+                  zh-tw-lang="相關工具"
+                  zh-cn-lang="工具"
+                  ru-lang="Инструменты"
+                  ko-lang="도구"
+                  ja-lang="ツール"
+                  es-lang="Herramientas"
+                  >Tools</a>
+                </li>
+                <li><a href="<?cs var:toroot ?>google/index.html">Google Services</a>
+                </li>
+                <?cs if:android.hasSamples ?>
+                  <li><a href="<?cs var:toroot ?>samples/index.html">Samples</a>
+                  </li>
+                <?cs /if ?>
+              </ul>
+            </li>
+            <li class="distribute last">
+              <ul>
+                <li><a href="<?cs var:toroot ?>distribute/googleplay/index.html">Google Play</a></li>
+                <li><a href="<?cs var:toroot ?>distribute/essentials/index.html">Essentials</a></li>
+                <li><a href="<?cs var:toroot ?>distribute/users/index.html">Get Users</a></li>
+                <li><a href="<?cs var:toroot ?>distribute/engage/index.html">Engage &amp; Retain</a></li>
+                <li><a href="<?cs var:toroot ?>distribute/monetize/index.html">Monetize</a></li>
+                <li><a href="<?cs var:toroot ?>distribute/tools/index.html">Tools &amp; Reference</a></li>
+                <li><a href="<?cs var:toroot ?>distribute/stories/index.html">Developer Stories</a></li>
+              </ul>
+            </li>
+          </ul>
+        </div><!-- /Expanded quicknav -->
+      </div><!-- end header-wrap.wrap -->
+    </div><!-- end header -->
+
+  <?cs if:about || wear || tv || auto ?>
+    <!-- Secondary x-nav -->
+    <div id="nav-x">
+        <div class="wrap">
+            <ul class="nav-x col-9 about" style="width:100%">
+                <li class="about"><a href="<?cs var:toroot ?>about/index.html"
+                  >About</a></li>
+                <li class="wear"><a href="<?cs var:toroot ?>wear/index.html"
+                  >Wear</a></li>
+                <li class="tv"><a href="<?cs var:toroot ?>tv/index.html"
+                  >TV</a></li>
+                <li class="auto"><a href="<?cs var:toroot ?>auto/index.html"
+                  >Auto</a></li>
             </ul>
-            
-            <!-- New Search -->
-            <div class="menu-container">
-            <div class="moremenu">
-    <div id="more-btn"></div>
-  </div>
-  <div class="morehover" id="moremenu">
-    <div class="top"></div>
-    <div class="mid">
-      <div class="header">Links</div>
-      <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
-        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
-        <li><a href="<?cs var:toroot ?>about/index.html">About Android</a></li>
-      </ul>
-      <div class="header">Android Sites</div>
-      <ul>
-        <li><a href="http://www.android.com">Android.com</a></li>
-        <li class="active"><a>Android Developers</a></li>
-        <li><a href="http://source.android.com">Android Open Source Project</a></li>
-      </ul>
-      
-      <?cs # Include language switcher only in online docs ?>
-      <?cs if:android.whichdoc == "online" ?>
-        <div class="header">Language</div>
-          <div id="language" class="locales">
-            <select name="language" onChange="changeLangPref(this.value, true)">
-                <option value="en">English</option>
-                <option value="es">Español</option>
-                <option value="ja">日本語</option>
-                <option value="ko">한국어</option>
-                <option value="ru">Русский</option>
-                <option value="zh-cn">中文 (中国)</option>
-                <option value="zh-tw">中文 (台灣)</option>
-            </select>
-          </div>
-        <script type="text/javascript">
-          <!--
-          loadLangPref();
-            //-->
-        </script>
-      <?cs /if ?>
-      <?cs # End of lang switcher ?>
-
-
-      <br class="clearfix" />
-    </div>
-    <div class="bottom"></div>
-  </div>
-  <div class="search" id="search-container">
-    <div class="search-inner">
-      <div id="search-btn"></div>
-      <div class="left"></div>
-      <form onsubmit="return submit_search()">
-        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '<?cs var:toroot ?>')" 
-onkeyup="return search_changed(event, false, '<?cs var:toroot ?>')" />
-      </form>
-      <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div>
-
-  <div class="search_filtered_wrapper reference">
-    <div class="suggest-card reference no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div>
-
-  <div class="search_filtered_wrapper docs">
-    <div class="suggest-card dummy no-display">&nbsp;</div>
-    <div class="suggest-card develop no-display">
-      <ul class="search_filtered">
-      </ul>
-      <div class="child-card guides no-display">
-      </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">
-      </ul>
-    </div>
-    <div class="suggest-card distribute no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div>
-
-  </div>
-  <!-- /New Search>
-          
-          
-          <!-- Expanded quicknav -->
-           <div id="quicknav" class="col-9">
-                <ul>
-                    <li class="design">
-                      <ul>
-                        <li><a href="<?cs var:toroot ?>design/index.html">Get Started</a></li>
-                        <li><a href="<?cs var:toroot ?>design/style/index.html">Style</a></li>
-                        <li><a href="<?cs var:toroot ?>design/patterns/index.html">Patterns</a></li>
-                        <li><a href="<?cs var:toroot ?>design/building-blocks/index.html">Building Blocks</a></li>
-                        <li><a href="<?cs var:toroot ?>design/downloads/index.html">Downloads</a></li>
-                        <li><a href="<?cs var:toroot ?>design/videos/index.html">Videos</a></li>
-                      </ul>
-                    </li>
-                    <li class="develop">
-                      <ul>
-                        <li><a href="<?cs var:toroot ?>training/index.html"
-                          zh-tw-lang="訓練課程"
-                          zh-cn-lang="培训"
-                          ru-lang="Курсы"
-                          ko-lang="교육"
-                          ja-lang="トレーニング"
-                          es-lang="Capacitación"               
-                          >Training</a></li>
-                        <li><a href="<?cs var:toroot ?>guide/index.html"
-                          zh-tw-lang="API 指南"
-                          zh-cn-lang="API 指南"
-                          ru-lang="Руководства по API"
-                          ko-lang="API 가이드"
-                          ja-lang="API ガイド"
-                          es-lang="Guías de la API"               
-                          >API Guides</a></li>
-                        <li><a href="<?cs var:toroot ?>reference/packages.html"
-                          zh-tw-lang="參考資源"
-                          zh-cn-lang="参考"
-                          ru-lang="Справочник"
-                          ko-lang="참조문서"
-                          ja-lang="リファレンス"
-                          es-lang="Referencia"               
-                          >Reference</a></li>
-                        <li><a href="<?cs var:toroot ?>tools/index.html"
-                          zh-tw-lang="相關工具"
-                          zh-cn-lang="工具"
-                          ru-lang="Инструменты"
-                          ko-lang="도구"
-                          ja-lang="ツール"
-                          es-lang="Herramientas"               
-                          >Tools</a>
-                          <ul><li><a href="<?cs var:toroot ?>sdk/index.html">Get the SDK</a></li></ul>
-                        </li>
-                        <li><a href="<?cs var:toroot ?>google/index.html">Google Services</a>
-                        </li>
-                        <?cs if:android.hasSamples ?>
-                          <li><a href="<?cs var:toroot ?>samples/index.html">Samples</a>
-                          </li>
-                        <?cs /if ?>
-                      </ul>
-                    </li>
-                    <li class="distribute last">
-                      <ul>
-                        <li><a href="<?cs var:toroot ?>distribute/index.html">Google Play</a></li>
-                        <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/index.html">Publishing</a></li>
-                        <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/index.html">Promoting</a></li>
-                        <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/index.html">App Quality</a></li>
-                        <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/index.html">Spotlight</a></li>
-                        <li><a href="<?cs var:toroot ?>distribute/open.html">Open Distribution</a></li>
-                      </ul>
-                    </li>
-                </ul>
-          </div>
-          <!-- /Expanded quicknav -->
         </div>
     </div>
-    <!-- /Header -->
-    
-    
-  <div id="searchResults" class="wrap" style="display:none;">
-          <h2 id="searchTitle">Results</h2>
-          <div id="leftSearchControl" class="search-control">Loading...</div>
-  </div>
-    
-    
-  <?cs if:training || guide || reference || tools || develop || google || samples ?>
+    <!-- /Sendondary x-nav ABOUT -->
+
+
+
+  <?cs elif:training || guide || reference || tools || develop || google || samples ?>
     <!-- Secondary x-nav -->
     <div id="nav-x">
         <div class="wrap">
@@ -231,7 +165,7 @@
                   ru-lang="Курсы"
                   ko-lang="교육"
                   ja-lang="トレーニング"
-                  es-lang="Capacitación"               
+                  es-lang="Capacitación"
                   >Training</a></li>
                 <li class="guide"><a href="<?cs var:toroot ?>guide/index.html"
                   zh-tw-lang="API 指南"
@@ -239,7 +173,7 @@
                   ru-lang="Руководства по API"
                   ko-lang="API 가이드"
                   ja-lang="API ガイド"
-                  es-lang="Guías de la API"               
+                  es-lang="Guías de la API"
                   >API Guides</a></li>
                 <li class="reference"><a href="<?cs var:toroot ?>reference/packages.html"
                   zh-tw-lang="參考資源"
@@ -247,9 +181,9 @@
                   ru-lang="Справочник"
                   ko-lang="참조문서"
                   ja-lang="リファレンス"
-                  es-lang="Referencia"               
+                  es-lang="Referencia"
                   >Reference</a></li>
-                <li class="tools"><a href="<?cs var:toroot ?>tools/index.html"
+                <li class="tools"><a href="<?cs var:toroot ?>sdk/index.html"
                   zh-tw-lang="相關工具"
                   zh-cn-lang="工具"
                   ru-lang="Инструменты"
@@ -267,13 +201,101 @@
                 <?cs /if ?>
             </ul>
         </div>
-        
     </div>
-    <!-- /Sendondary x-nav -->
+    <!-- /Sendondary x-nav DEVELOP -->
+
+  <?cs elif:distribute || googleplay || essentials || users || engage || monetize || disttools || stories ?>
+    <!-- Secondary distribute x-nav -->
+    <div id="nav-x">
+        <div class="wrap">
+            <ul class="nav-x distribute">
+                <li class="googleplay"><a href="<?cs var:toroot ?>distribute/googleplay/index.html"
+                  >Google Play</a></li>
+                <li class="essentials"><a href="<?cs var:toroot ?>distribute/essentials/index.html"
+                  >Essentials</a></li>
+                <li class="users"><a href="<?cs var:toroot ?>distribute/users/index.html"
+                  >Get Users</a></li>
+                <li class="engage"><a href="<?cs var:toroot ?>distribute/engage/index.html"
+                  >Engage &amp; Retain</a></li>
+                <li class="monetize"><a href="<?cs var:toroot ?>distribute/monetize/index.html"
+                  >Monetize</a>
+                </li>
+                <li class="disttools"><a href="<?cs var:toroot ?>distribute/tools/index.html"
+                  >Tools</a>
+                </li>
+                <li class="stories"><a href="<?cs var:toroot ?>distribute/stories/index.html"
+                  >Stories</a>
+                </li>
+            </ul>
+            <a href="https://play.google.com/apps/publish/" class="developer-console-btn">Developer Console</a>
+        </div> <!-- /Secondary distribute x-nav -->
+    </div>
+    <!-- /Sendondary x-nav DISTRIBUTE -->
   <?cs /if ?>
 
-<?cs /if ?>
-<?cs # end if/else !devsite ?>
+    <div id="searchResults" class="wrap" style="display:none;">
+      <h2 id="searchTitle">Results</h2>
+      <div id="leftSearchControl" class="search-control">Loading...</div>
+    </div>
+  </div> <!--end header-wrapper -->
 
-  <?cs 
+  <div id="sticky-header">
+    <div>
+      <a class="logo" href="#top"></a>
+      <a class="top" href="#top"></a>
+      <ul class="breadcrumb">
+        <?cs # More <li> elements added here with javascript ?>
+        <?cs if:!section.landing ?><li class="current"><?cs var:page.title ?></li><?cs
+        /if ?>
+      </ul>
+    </div>
+  </div>
+
+<?cs /if ?><?cs # end if/else !devsite ?>
+<?cs /if ?><?cs # end if/else preview ?><?cs
+/def ?>
+
+<?cs def:preview_masthead() ?>
+<a name="top"></a>
+
+
+<!-- Header -->
+<div id="header-wrapper">
+  <div id="header">
+    <div class="wrap" id="header-wrap">
+      <div class="col_3 logo landing-logo" style="width:240px">
+        <a href="<?cs var:toroot ?>preview/index.html">
+          <img src="<?cs var:toroot ?>assets/images/android.png" height="25" alt="Android"
+            style="margin:-3px 0 0" />
+        </a>
+      </div>
+      <div class="col-8" style="margin:0"><h1 style="margin: 4px 0 0 0px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:27px;">L Developer Preview</h1></div>
+
+      <?cs # ADD SEARCH AND MENU ?>
+      <?cs call:header_search_widget() ?>
+
+    </div><!-- end header-wrap -->
+  </div><!-- /Header -->
+
+
+  <div id="searchResults" class="wrap" style="display:none;">
+          <h2 id="searchTitle">Results</h2>
+          <div id="leftSearchControl" class="search-control">Loading...</div>
+  </div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+  <div>
+    <a class="logo" href="#top"></a>
+    <a class="top" href="#top"></a>
+    <ul class="breadcrumb">
+      <?cs # More <li> elements added here with javascript ?>
+      <?cs if:!section.landing ?><li class="current"><?cs var:page.title ?></li><?cs
+      /if ?>
+    </ul>
+  </div>
+</div>
+
+  <?cs
 /def ?>
diff --git a/tools/droiddoc/templates-sdk/customizations.cs b/tools/droiddoc/templates-sdk/customizations.cs
index ed57f1c..e0e3ca1 100644
--- a/tools/droiddoc/templates-sdk/customizations.cs
+++ b/tools/droiddoc/templates-sdk/customizations.cs
@@ -7,7 +7,6 @@
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <?cs 
         include:"../../../../frameworks/base/docs/html/sdk/sdk_toc.cs" ?>
@@ -15,33 +14,16 @@
 
       </div>
     </div> <!-- end side-nav -->
-<?cs /def ?>
-<?cs 
-def:resources_tab_nav() ?>
+<?cs /def ?><?cs
+
+def:no_nav() ?>
   <div class="wrap clearfix" id="body-content">
-    <a
-    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
-      <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
+<?cs /def ?><?cs
 
-<?cs 
-        include:"../../../../frameworks/base/docs/html/resources/resources_toc.cs" ?>
-
-
-      </div>
-    </div> <!-- end side-nav -->
-    <script>
-      $(document).ready(function() {
-        scrollIntoView("devdoc-nav");
-        });
-    </script>
-<?cs /def ?>
-<?cs
 def:tools_nav() ?>
   <div class="wrap clearfix" id="body-content">
     <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 <?cs 
         include:"../../../../frameworks/base/docs/html/tools/tools_toc.cs" ?>
         
@@ -59,7 +41,6 @@
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 
 <?cs 
@@ -73,14 +54,110 @@
         scrollIntoView("devdoc-nav");
         });
     </script>
-<?cs /def ?>
-<?cs 
+<?cs /def ?><?cs
+
+def:googleplay_nav() ?>
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+<?cs include:"../../../../frameworks/base/docs/html/distribute/googleplay/googleplay_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?><?cs
+
+def:essentials_nav() ?>
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+<?cs include:"../../../../frameworks/base/docs/html/distribute/essentials/essentials_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?><?cs
+
+def:users_nav() ?>
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+<?cs include:"../../../../frameworks/base/docs/html/distribute/users/users_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?><?cs
+
+def:engage_nav() ?>
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+<?cs include:"../../../../frameworks/base/docs/html/distribute/engage/engage_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?><?cs
+
+def:monetize_nav() ?>
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+<?cs include:"../../../../frameworks/base/docs/html/distribute/monetize/monetize_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?><?cs
+
+def:disttools_nav() ?>
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+<?cs include:"../../../../frameworks/base/docs/html/distribute/tools/disttools_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?><?cs
+
+def:stories_nav() ?>
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+<?cs include:"../../../../frameworks/base/docs/html/distribute/stories/stories_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?><?cs
+
 def:guide_nav() ?>
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
-
 
 <?cs 
         include:"../../../../frameworks/base/docs/html/guide/guide_toc.cs" ?>
@@ -99,7 +176,6 @@
   <div class="wrap clearfix" id="body-content">
     <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 
 <?cs
@@ -119,7 +195,6 @@
   <div class="wrap clearfix" id="body-content">
     <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <?cs
         include:"../../../../frameworks/base/docs/html/distribute/distribute_toc.cs" ?>
@@ -139,7 +214,6 @@
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <?cs
         include:"../../../../frameworks/base/docs/html/samples/samples_toc.cs" ?>
@@ -159,7 +233,6 @@
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <?cs
         include:"../../../../frameworks/base/docs/html/google/google_toc.cs" ?>
@@ -183,7 +256,6 @@
   <div class="wrap clearfix" id="body-content">
     <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <?cs
         include:"../../../../frameworks/base/docs/html/about/about_toc.cs" ?>
@@ -198,6 +270,42 @@
     </script>
 <?cs /def ?>
 
+
+<?cs
+def:wear_nav() ?>
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+
+<?cs
+        include:"../../../../frameworks/base/docs/html/wear/wear_toc.cs" ?>
+
+
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?>
+
+<?cs
+def:preview_nav() ?>
+  <div class="wrap clearfix" id="body-content">
+    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
+      <div id="devdoc-nav" class="scroll-pane">
+        <?cs
+          include:"../../../../frameworks/base/docs/html/preview/preview_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      $(document).ready(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?>
+
 <?cs # The default side navigation for the reference docs ?><?cs 
 def:default_left_nav() ?>
 <?cs if:reference.gcm || reference.gms ?>
@@ -206,8 +314,6 @@
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav">
-
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
       <div id="api-nav-header">
         <div id="api-level-toggle">
           <label for="apiLevelCheckbox" class="disabled"
@@ -247,6 +353,7 @@
 <?cs 
             if:subcount(class.package) ?>
             <ul>
+              <?cs call:list("Annotations", class.package.annotations) ?>
               <?cs call:list("Interfaces", class.package.interfaces) ?>
               <?cs call:list("Classes", class.package.classes) ?>
               <?cs call:list("Enums", class.package.enums) ?>
@@ -255,6 +362,7 @@
             </ul><?cs 
             elif:subcount(package) ?>
             <ul>
+              <?cs call:class_link_list("Annotations", package.annotations) ?>
               <?cs call:class_link_list("Interfaces", package.interfaces) ?>
               <?cs call:class_link_list("Classes", package.classes) ?>
               <?cs call:class_link_list("Enums", package.enums) ?>
@@ -308,10 +416,111 @@
     <?cs 
 /def ?>
 
+
+<?cs
+def:header_search_widget() ?>
+<div class="menu-container">
+  <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
+  <div class="morehover" id="moremenu">
+    <div class="top"></div>
+    <div class="mid">
+      <div class="header">Links</div>
+      <ul>
+        <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
+        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
+        <li><a href="<?cs var:toroot ?>about/index.html">About Android</a></li>
+      </ul>
+      <div class="header">Android Sites</div>
+      <ul>
+        <li><a href="http://www.android.com">Android.com</a></li>
+        <li class="active"><a>Android Developers</a></li>
+        <li><a href="http://source.android.com">Android Open Source Project</a></li>
+      </ul>
+
+      <?cs # Include language switcher only in online docs ?>
+      <?cs if:android.whichdoc == "online" ?>
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      <?cs /if ?>
+      <?cs # End of lang switcher ?>
+      <br class="clearfix" />
+    </div><!-- end 'mid' -->
+    <div class="bottom"></div>
+  </div><!-- end 'moremenu' -->
+
+  <div class="search" id="search-container">
+    <div class="search-inner">
+      <div id="search-btn"></div>
+      <div class="left"></div>
+      <form onsubmit="return submit_search()">
+        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
+          onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+          onkeydown="return search_changed(event, true, '<?cs var:toroot ?>')"
+          onkeyup="return search_changed(event, false, '<?cs var:toroot ?>')" />
+      </form>
+      <div class="right"></div>
+      <a class="close hide">close</a>
+      <div class="left"></div>
+      <div class="right"></div>
+    </div><!-- end search-inner -->
+  </div><!-- end search-container -->
+
+  <div class="search_filtered_wrapper reference">
+    <div class="suggest-card reference no-display">
+      <ul class="search_filtered">
+      </ul>
+    </div>
+  </div>
+
+  <div class="search_filtered_wrapper docs">
+    <div class="suggest-card dummy no-display">&nbsp;</div>
+    <div class="suggest-card develop no-display">
+      <ul class="search_filtered">
+      </ul>
+      <div class="child-card guides no-display">
+      </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">
+      </ul>
+    </div>
+    <div class="suggest-card distribute no-display">
+      <ul class="search_filtered">
+      </ul>
+    </div>
+  </div>
+</div><!-- end menu-container (search and menu widget) -->
+<?cs /def ?>
+
+
+
 <?cs 
 def:custom_left_nav() ?><?cs
-  if:fullpage ?><?cs 
-    call:fullpage() ?><?cs 
+  if:fullpage ?><?cs
+    call:fullpage() ?><?cs
+  elif:nonavpage ?><?cs
+    call:no_nav() ?><?cs
   elif:guide ?><?cs 
     call:guide_nav() ?><?cs 
   elif:design ?><?cs
@@ -324,15 +533,33 @@
     call:google_nav() ?><?cs 
   elif:samples ?><?cs
     call:samples_nav() ?><?cs
-  elif:more ?><?cs 
-    call:dist_more_nav() ?><?cs
   elif:distribute ?><?cs 
-    call:distribute_nav() ?><?cs 
-  elif:about ?><?cs 
-    call:about_nav() ?><?cs 
-  else ?><?cs 
-    call:default_left_nav() ?> <?cs 
-  /if ?><?cs 
+    if:googleplay ?><?cs
+      call:googleplay_nav() ?><?cs
+    elif:essentials ?><?cs
+      call:essentials_nav() ?><?cs
+    elif:users ?><?cs
+      call:users_nav() ?><?cs
+    elif:engage ?><?cs
+      call:engage_nav() ?><?cs
+    elif:monetize ?><?cs
+      call:monetize_nav() ?><?cs
+    elif:disttools ?><?cs
+      call:disttools_nav() ?><?cs
+    elif:stories ?><?cs
+      call:stories_nav() ?><?cs
+    /if ?><?cs
+  elif:about ?><?cs
+    call:about_nav() ?><?cs
+  elif:distribute ?><?cs
+    call:distribute_nav() ?><?cs
+  elif:wear ?><?cs
+    call:wear_nav() ?><?cs
+  elif:preview ?><?cs
+    call:preview_nav() ?><?cs
+  else ?><?cs
+    call:default_left_nav() ?> <?cs
+  /if ?><?cs
 /def ?>
 
 <?cs # appears at the bottom of every page ?><?cs 
diff --git a/tools/droiddoc/templates-sdk/docpage.cs b/tools/droiddoc/templates-sdk/docpage.cs
index ea462c9..7d872bc 100644
--- a/tools/droiddoc/templates-sdk/docpage.cs
+++ b/tools/droiddoc/templates-sdk/docpage.cs
@@ -2,19 +2,36 @@
 <?cs include:"macros.cs" ?>
 <html<?cs if:devsite ?> devsite<?cs /if ?>>
 <?cs include:"head_tag.cs" ?>
-<body class="gc-documentation <?cs if:(google || reference.gms || reference.gcm) ?>google<?cs /if ?>
-  <?cs if:(guide||develop||training||reference||tools||sdk||samples) ?>develop<?cs if:guide ?> guide<?cs /if ?><?cs if:samples ?> samples<?cs /if ?><?cs
-  elif:about ?>about<?cs
-  elif:design ?>design<?cs
-  elif:distribute ?>distribute<?cs
-  /if ?><?cs
-  if:page.trainingcourse ?> trainingcourse<?cs /if ?>" itemscope itemtype="http://schema.org/Article">
-<?cs include:"header.cs" ?>
+<body class="gc-documentation
 
-<div <?cs if:fullpage
-?>class="fullpage"<?cs elif:design||tools||about||sdk||distribute
-?>class="col-13" id="doc-col"<?cs else
-?>class="col-12" id="doc-col"<?cs /if ?> >
+<?cs
+if:(google || reference.gms || reference.gcm) ?>google<?cs /if ?><?cs
+  if:(guide||develop||training||reference||tools||sdk||samples) ?>develop<?cs
+    if:guide ?> guide<?cs /if ?><?cs
+    if:samples ?> samples<?cs /if ?><?cs
+  elif:(distribute||googleplay||essentials||users||engage||monetize||disttools||stories)
+    ?>distribute<?cs
+    if:googleplay ?> googleplay<?cs /if ?><?cs
+    if:essentials ?> essentials<?cs /if ?><?cs
+    if:users ?> users<?cs /if ?><?cs
+    if:engage ?> engage<?cs /if ?><?cs
+    if:monetize ?> monetize<?cs /if ?><?cs
+    if:disttools ?> disttools<?cs /if ?><?cs
+    if:stories ?> stories<?cs /if ?><?cs
+  elif:(about||wear||tv||auto) ?>about<?cs
+  elif:design ?>design<?cs
+/if ?><?cs
+if:page.trainingcourse ?> trainingcourse<?cs
+/if ?>" itemscope itemtype="http://schema.org/Article"><?cs
+include:"header.cs" ?>
+
+<div <?cs
+  if:fullpage
+    ?>class="fullpage"<?cs
+  elif:(design||tools||about||sdk||googleplay||essentials||users||monetize||disttools) && !nonavpage
+    ?>class="col-13" id="doc-col"<?cs
+  elif:!nonavpage
+    ?>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 ?>
   <?cs if:header.hide ?>
@@ -73,7 +90,8 @@
       </div>
     <?cs /if ?><?cs # end if training ?>
   </div>
-  <?cs /if ?>
+  <?cs /if ?><?cs # end if header.hide ?>
+
 <?cs elif:samplesProjectIndex ?>
   <div id="api-info-block">
   <div class="sum-details-links">
@@ -83,7 +101,17 @@
   </div><!-- end sum-details-links -->
   </div><!-- end breadcurmb block -->
   <h1 itemprop="name"><?cs var:projectDir ?></h1>
+
 <?cs else ?>
+  <?cs if:training ?>
+<?cs # horrible horrible hack to move TOC up when the next/prev links are not there ?>
+<style>
+  #tb-wrapper {
+    margin-top:6px;
+  }
+</style>
+  <?cs /if ?>
+
   <?cs if:(!fullpage && !header.hide) ?>
     <?cs if:page.landing ?><?cs # header logic for docs that are landing pages ?>
       <div class="landing-banner">
@@ -129,25 +157,9 @@
                     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">
+        <div class="paging-links layout-content-col col-10">
           <?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="下一课"
@@ -164,35 +176,29 @@
                 ja-lang="開始する"
                 es-lang="Empezar"
                 >Get started</a>
+            <a href="#" class="next-class-link hide">Next class</a>
+          <?cs /if ?>
+        </div>
+        <div class="layout-content-col plus-container col-2" >
+          <?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 ?>
       </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" ?>
 </div><!-- end doc-content -->
 
 <?cs include:"trailer.cs" ?>
+  <script src="https://developer.android.com/ytblogger_lists_unified.js" type="text/javascript"></script>
+  <script src="<?cs var:toroot ?>jd_lists_unified.js?v=2" type="text/javascript"></script>
+  <script src="<?cs var:toroot ?>jd_extras.js?v=3" type="text/javascript"></script>
+  <script src="<?cs var:toroot ?>jd_collections.js?v=3" type="text/javascript"></script>
+  <script src="<?cs var:toroot ?>jd_tag_helpers.js?v=2" type="text/javascript"></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/head_tag.cs b/tools/droiddoc/templates-sdk/head_tag.cs
index 54de169..7ecb7f9 100644
--- a/tools/droiddoc/templates-sdk/head_tag.cs
+++ b/tools/droiddoc/templates-sdk/head_tag.cs
@@ -15,13 +15,13 @@
 ?><?cs
   # END if/else devsite ?>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="viewport" content="width=device-width" />
+<meta name="viewport" content="width=<?cs
+  if:page.viewport_width ?><?cs
+    var:page.viewport_width ?><?cs
+  else ?>device-width<?cs /if ?>" />
 <?cs
   if:page.metaDescription ?>
 <meta name="Description" content="<?cs var:page.metaDescription ?>"><?cs
-  /if ?><?cs
-  if:page.customHeadTag ?>
-<?cs var:page.customHeadTag ?><?cs
   /if ?>
 <link rel="shortcut icon" type="image/x-icon" href="<?cs var:toroot ?>favicon.ico" />
 <title><?cs 
@@ -31,10 +31,16 @@
 
 <!-- STYLESHEETS -->
 <link rel="stylesheet"
-href="<?cs if:android.whichdoc != 'online' ?>http:<?cs /if ?>//fonts.googleapis.com/css?family=Roboto:regular,medium,thin,italic,mediumitalic,bold" title="roboto">
-<link href="<?cs var:toroot ?>assets/css/default.css" rel="stylesheet" type="text/css">
+href="<?cs
+if:android.whichdoc != 'online' ?>http:<?cs
+/if ?>//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="<?cs
+if:android.whichdoc != 'online' ?>http:<?cs
+/if ?>//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
+<link href="<?cs var:toroot ?>assets/css/default.css?v=2" rel="stylesheet" type="text/css">
 
-<?cs if:reference && !(reference.gms || reference.gcm) ?>
+<?cs if:reference && !(reference.gms || reference.gcm || preview) ?>
 <!-- FULLSCREEN STYLESHEET -->
 <link href="<?cs var:toroot ?>assets/css/fullscreen.css" rel="stylesheet" class="fullscreen"
 type="text/css">
@@ -47,23 +53,27 @@
   ?><script src="<?cs var:toroot ?>_static/js/android_3p-bundle.js" type="text/javascript"></script><?cs
 else
   ?><script src="<?cs var:toroot ?>assets/js/android_3p-bundle.js" type="text/javascript"></script><?cs
-/if ?>
+/if ?><?cs
+  if:page.customHeadTag ?>
+<?cs var:page.customHeadTag ?><?cs
+  /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>
+<script src="<?cs var:toroot ?>assets/js/docs.js?v=2" type="text/javascript"></script>
 
-<script type="text/javascript">
-  var _gaq = _gaq || [];
-  _gaq.push(['_setAccount', 'UA-5831155-1']);
-  _gaq.push(['_trackPageview']);
+<script>
+  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
 
-  (function() {
-    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-  })();
+  ga('create', 'UA-5831155-1', 'android.com');
+  ga('create', 'UA-49880327-2', 'android.com', {'name': 'universal'});  // New tracker);
+  ga('send', 'pageview');
+  ga('universal.send', 'pageview'); // Send page view for new tracker.
 </script>
-</head>
\ No newline at end of file
+
+</head>
diff --git a/tools/droiddoc/templates-sdk/macros_override.cs b/tools/droiddoc/templates-sdk/macros_override.cs
new file mode 100644
index 0000000..1525be5
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/macros_override.cs
@@ -0,0 +1,36 @@
+<?cs # Create a comma separated list of annotations on obj that were in showAnnotations in Doclava ?>
+<?cs # pre is an HTML string to start the list, post is an HTML string to close the list ?>
+<?cs # for example call:show_annotations_list(cl, "<td>Annotations: ", "</td>") ?>
+<?cs # if obj has nothing on obj.showAnnotations, nothing will be output ?>
+<?cs def:show_annotations_list(obj) ?>
+    <?cs each:anno = obj.showAnnotations ?>
+      <?cs if:first(anno) ?>
+        <span class='annotation-message'>
+          Included in documention by the annotations:
+      <?cs /if ?>
+      @<?cs var:anno.type.label ?>
+      <?cs if:last(anno) == 0 ?>
+        , &nbsp;
+      <?cs /if ?>
+      <?cs if:last(anno)?>
+        </span>
+      <?cs /if ?>
+    <?cs /each ?>
+<?cs /def ?>
+
+<?cs # Override default class_link_table to display annotations ?>
+<?cs def:class_link_table(classes) ?>
+  <?cs set:count = #1 ?>
+  <table class="jd-sumtable-expando">
+    <?cs each:cl=classes ?>
+      <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:cl.type.since ?>" >
+        <td class="jd-linkcol"><?cs call:type_link(cl.type) ?></td>
+        <td class="jd-descrcol" width="100%">
+          <?cs call:short_descr(cl) ?>&nbsp;
+          <?cs call:show_annotations_list(cl) ?>
+        </td>
+      </tr>
+      <?cs set:count = count + #1 ?>
+    <?cs /each ?>
+  </table>
+<?cs /def ?>
\ No newline at end of file
diff --git a/tools/droiddoc/templates-sdk/package.cs b/tools/droiddoc/templates-sdk/package.cs
index 99eaff2..2225565 100644
--- a/tools/droiddoc/templates-sdk/package.cs
+++ b/tools/droiddoc/templates-sdk/package.cs
@@ -1,10 +1,13 @@
 <?cs include:"doctype.cs" ?>
 <?cs include:"macros.cs" ?>
+<?cs include:"macros_override.cs" ?>
 <html<?cs if:devsite ?> devsite<?cs /if ?>>
 <?cs include:"head_tag.cs" ?>
 
 <body class="gc-documentation <?cs if:(reference.gms || reference.gcm) ?>google<?cs /if ?>
   <?cs if:(guide||develop||training||reference||tools||sdk) ?>develop<?cs
+    if:reference ?> reference<?cs
+    /if ?><?cs
   elif:design ?>design<?cs
   elif:distribute ?>distribute<?cs
   /if ?>">
@@ -45,6 +48,7 @@
   <?cs /if ?>
 <?cs /def ?>
 
+<?cs call:class_table("Annotations", package.annotations) ?>
 <?cs call:class_table("Interfaces", package.interfaces) ?>
 <?cs call:class_table("Classes", package.classes) ?>
 <?cs call:class_table("Enums", package.enums) ?>
diff --git a/tools/droiddoc/templates-sdk/packages.cs b/tools/droiddoc/templates-sdk/packages.cs
index 44680c3..5056d3a 100644
--- a/tools/droiddoc/templates-sdk/packages.cs
+++ b/tools/droiddoc/templates-sdk/packages.cs
@@ -4,6 +4,8 @@
 <?cs include:"head_tag.cs" ?>
 <body class="gc-documentation <?cs if:(reference.gms || reference.gcm) ?>google<?cs /if ?>
   <?cs if:(guide||develop||training||reference||tools||sdk) ?>develop<?cs
+    if:reference ?> reference<?cs
+    /if ?><?cs
   elif:design ?>design<?cs
   elif:distribute ?>distribute<?cs
   /if ?>">
diff --git a/tools/droiddoc/templates-sdk/sample.cs b/tools/droiddoc/templates-sdk/sample.cs
index c6f28f8..32a0788 100644
--- a/tools/droiddoc/templates-sdk/sample.cs
+++ b/tools/droiddoc/templates-sdk/sample.cs
@@ -18,7 +18,7 @@
   <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"
-    onclick="_gaq.push(['_trackEvent', 'Samples', 'Download', <?cs var:projectDir ?>]);"
+    onclick="ga('send', 'event', 'Samples', 'Download', <?cs var:projectDir ?>);"
     >Download</a>
 
 </div><!-- end sum-details-links -->
diff --git a/tools/droiddoc/templates-sdk/sampleindex.cs b/tools/droiddoc/templates-sdk/sampleindex.cs
index 98767b1..1bacb53 100644
--- a/tools/droiddoc/templates-sdk/sampleindex.cs
+++ b/tools/droiddoc/templates-sdk/sampleindex.cs
@@ -21,7 +21,7 @@
 &#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"
-    onclick="_gaq.push(['_trackEvent', 'Samples', 'Download', <?cs var:projectDir ?>]);"
+    onclick="ga('send', 'event', 'Samples', 'Download', <?cs var:projectDir ?>);"
     >Download</a>
 
 </div><!-- end sum-details-links -->
diff --git a/tools/droiddoc/templates-sdk/sdkpage.cs b/tools/droiddoc/templates-sdk/sdkpage.cs
index 95f6596..a069b1d 100644
--- a/tools/droiddoc/templates-sdk/sdkpage.cs
+++ b/tools/droiddoc/templates-sdk/sdkpage.cs
@@ -77,7 +77,7 @@
 
   <table class="download" id="download-table">
     <tr>
-      <th>Platform</th>
+      <th>Platform<br>(32-bit target)</th>
       <th>Package</th>
       <th style="white-space:nowrap">Size (Bytes)</th>
       <th>MD5 Checksum</th>
@@ -183,8 +183,117 @@
     <td><?cs var:ndk.linux64.legacy_bytes ?></td>
     <td><?cs var:ndk.linux64.legacy_checksum ?></td>
   </tr> -->
+
     <tr>
-      <th>Additional Download</th>
+      <th>Platform<br>(64-bit target)</th>
+      <th>Package</th>
+      <th style="white-space:nowrap">Size (Bytes)</th>
+      <th>MD5 Checksum</th>
+  </tr>
+  <tr>
+    <td>Windows 32-bit</td>
+    <td>
+  <a onClick="return onDownload(this)"
+     href="http://dl.google.com/android/ndk/<?cs var:ndk.win32_64_download ?>"><?cs var:ndk.win32_64_download ?></a>
+    </td>
+    <td><?cs var:ndk.win32_64_bytes ?></td>
+    <td><?cs var:ndk.win32_64_checksum ?></td>
+  </tr>
+ <!-- <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>
+    <td>Windows 64-bit</td>
+    <td>
+  <a onClick="return onDownload(this)"
+     href="http://dl.google.com/android/ndk/<?cs var:ndk.win64_64_download ?>"><?cs var:ndk.win64_64_download ?></a>
+    </td>
+    <td><?cs var:ndk.win64_64_bytes ?></td>
+    <td><?cs var:ndk.win64_64_checksum ?></td>
+  </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>
+    <td>Mac OS X 32-bit</td>
+    <td>
+  <a onClick="return onDownload(this)"
+     href="http://dl.google.com/android/ndk/<?cs var:ndk.mac32_64_download ?>"><?cs var:ndk.mac32_64_download ?></a>
+    </td>
+    <td><?cs var:ndk.mac32_64_bytes ?></td>
+    <td><?cs var:ndk.mac32_64_checksum ?></td>
+  </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> -->
+    <td>Mac OS X 64-bit</td>
+    <td>
+  <a onClick="return onDownload(this)"
+     href="http://dl.google.com/android/ndk/<?cs var:ndk.mac64_64_download ?>"><?cs var:ndk.mac64_64_download ?></a>
+    </td>
+    <td><?cs var:ndk.mac64_64_bytes ?></td>
+    <td><?cs var:ndk.mac64_64_checksum ?></td>
+  </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>
+    <td>Linux 32-bit (x86)</td>
+    <td>
+  <a onClick="return onDownload(this)"
+     href="http://dl.google.com/android/ndk/<?cs var:ndk.linux32_64_download ?>"><?cs var:ndk.linux32_64_download ?></a>
+    </td>
+    <td><?cs var:ndk.linux32_64_bytes ?></td>
+    <td><?cs var:ndk.linux32_64_checksum ?></td>
+  </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>
+    <td>Linux 64-bit (x86)</td>
+    <td>
+  <a onClick="return onDownload(this)"
+     href="http://dl.google.com/android/ndk/<?cs var:ndk.linux64_64_download ?>"><?cs var:ndk.linux64_64_download ?></a>
+    </td>
+    <td><?cs var:ndk.linux64_64_bytes ?></td>
+    <td><?cs var:ndk.linux64_64_checksum ?></td>
+  </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<br>(32-, 64-bit)</th>
       <th>Package</th>
       <th style="white-space:nowrap">Size (Bytes)</th>
       <th>MD5 Checksum</th>
@@ -280,7 +389,7 @@
 
 <h4><a href='' class="expandable"
   onclick="toggleExpandable(this,'.pax');hideExpandable('.myide,.reqs');return false;"
-  >DOWNLOAD FOR OTHER PLATFORMS</a></h4>
+  >VIEW ALL DOWNLOADS AND SIZES</a></h4>
 
 
 <div class="pax col-13 online" style="display:none;margin:0;">
@@ -298,7 +407,7 @@
     <td>Windows 32-bit</td>
     <td>
   <a onClick="return onDownload(this)" id="win-bundle32"
-     href="http://dl.google.com/android/adt/<?cs var:sdk.version ?>/<?cs var:sdk.win32_bundle_download ?>"><?cs var:sdk.win32_bundle_download ?></a>
+     href="https://dl.google.com/android/adt/<?cs var:sdk.win32_bundle_download ?>"><?cs var:sdk.win32_bundle_download ?></a>
     </td>
     <td><?cs var:sdk.win32_bundle_bytes ?> bytes</td>
     <td><?cs var:sdk.win32_bundle_checksum ?></td>
@@ -307,7 +416,7 @@
     <td>Windows 64-bit</td>
     <td>
   <a onClick="return onDownload(this)" id="win-bundle64"
-     href="http://dl.google.com/android/adt/<?cs var:sdk.version ?>/<?cs var:sdk.win64_bundle_download ?>"><?cs var:sdk.win64_bundle_download ?></a>
+     href="https://dl.google.com/android/adt/<?cs var:sdk.win64_bundle_download ?>"><?cs var:sdk.win64_bundle_download ?></a>
     </td>
     <td><?cs var:sdk.win64_bundle_bytes ?> bytes</td>
     <td><?cs var:sdk.win64_bundle_checksum ?></td>
@@ -316,7 +425,7 @@
     <td><nobr>Mac OS X 64-bit</nobr></td>
     <td>
   <a onClick="return onDownload(this)" id="mac-bundle64"
-     href="http://dl.google.com/android/adt/<?cs var:sdk.version ?>/<?cs var:sdk.mac64_bundle_download ?>"><?cs var:sdk.mac64_bundle_download ?></a>
+     href="https://dl.google.com/android/adt/<?cs var:sdk.mac64_bundle_download ?>"><?cs var:sdk.mac64_bundle_download ?></a>
     </td>
     <td><?cs var:sdk.mac64_bundle_bytes ?> bytes</td>
     <td><?cs var:sdk.mac64_bundle_checksum ?></td>
@@ -325,7 +434,7 @@
     <td>Linux 32-bit</td>
     <td>
   <a onClick="return onDownload(this)" id="linux-bundle32"
-     href="http://dl.google.com/android/adt/<?cs var:sdk.version ?>/<?cs var:sdk.linux32_bundle_download ?>"><?cs var:sdk.linux32_bundle_download ?></a>
+     href="https://dl.google.com/android/adt/<?cs var:sdk.linux32_bundle_download ?>"><?cs var:sdk.linux32_bundle_download ?></a>
     </td>
     <td><?cs var:sdk.linux32_bundle_bytes ?> bytes</td>
     <td><?cs var:sdk.linux32_bundle_checksum ?></td>
@@ -334,7 +443,7 @@
     <td>Linux 64-bit</td>
     <td>
   <a onClick="return onDownload(this)" id="linux-bundle64"
-     href="http://dl.google.com/android/adt/<?cs var:sdk.version ?>/<?cs var:sdk.linux64_bundle_download ?>"><?cs var:sdk.linux64_bundle_download ?></a>
+     href="https://dl.google.com/android/adt/<?cs var:sdk.linux64_bundle_download ?>"><?cs var:sdk.linux64_bundle_download ?></a>
     </td>
     <td><?cs var:sdk.linux64_bundle_bytes ?> bytes</td>
     <td><?cs var:sdk.linux64_bundle_checksum ?></td>
@@ -430,12 +539,12 @@
 
     /* set up primary adt download button */
     $('#download-bundle-button').show();
-    $('#download-bundle-button').append("Download the SDK <br/><span class='small'>ADT Bundle for " + os + "</span>");
+    $('#download-bundle-button').append("Download Eclipse ADT <br/><span class='small'>with the Android SDK for " + os + "</span>");
     $('#download-bundle-button').click(function() {return onDownload(this,true,true);}).attr('href', bundlename);
 
     /* set up sdk tools only button */
     $('#download-tools-button').show();
-    $('#download-tools-button').append("Download the SDK Tools for " + os);
+    $('#download-tools-button').append("Download the stand-alone Android SDK Tools for " + os);
     $('#download-tools-button').click(function() {return onDownload(this,true);}).attr('href', $toolslink.attr('href'));
   } else {
     $('.pax').show();
@@ -501,10 +610,19 @@
   function onDownloadForRealz(link) {
     if ($("input#agree").is(':checked') && $("#bitpicker input:checked").length) {
       $("div.sdk-terms").slideUp();
-      $("#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()]);
+      $("h1#tos-header").text('Now redirecting to the install instructions...');
+      $("#sdk-terms-form,.sdk-terms-intro").fadeOut('slow', function() {
+        setTimeout(function() {
+          if ($("#downloadForRealz").attr('bundle') == 'true') {
+            // User downloaded the ADT Bundle
+            window.location = "/sdk/installing/index.html?pkg=adt";
+          } else {
+            // User downloaded the SDK Tools
+            window.location = "/sdk/installing/index.html?pkg=tools";
+          }
+        }, 500);
+      });
+      ga('send', 'event', 'SDK', 'IDE and Tools', $("#downloadForRealz").html());
       return true;
     } else {
       $("label#agreeLabel,#bitpicker input").parent().stop().animate({color: "#258AAF"}, 200,
diff --git a/tools/post_process_props.py b/tools/post_process_props.py
index 32a90bc..030826d 100755
--- a/tools/post_process_props.py
+++ b/tools/post_process_props.py
@@ -16,6 +16,9 @@
 
 import sys
 
+# Usage: post_process_props.py file.prop [blacklist_key, ...]
+# Blacklisted keys are removed from the property file, if present
+
 # See PROP_NAME_MAX and PROP_VALUE_MAX system_properties.h.
 # The constants in system_properties.h includes the termination NUL,
 # so we decrease the values by 1 here.
@@ -88,8 +91,9 @@
     for line in self.lines:
       if not line or line.startswith("#"):
         continue
-      key, value = line.split("=", 1)
-      props[key] = value
+      if "=" in line:
+        key, value = line.split("=", 1)
+        props[key] = value
     return props
 
   def get(self, name):
@@ -107,6 +111,10 @@
         return
     self.lines.append(key + value)
 
+  def delete(self, name):
+    key = name + "="
+    self.lines = [ line for line in self.lines if not line.startswith(key) ]
+
   def write(self, f):
     f.write("\n".join(self.lines))
     f.write("\n")
@@ -130,6 +138,10 @@
   if not validate(properties):
     sys.exit(1)
 
+  # Drop any blacklisted keys
+  for key in argv[2:]:
+    properties.delete(key)
+
   f = open(filename, 'w+')
   properties.write(f)
   f.close()
diff --git a/tools/releasetools/add_img_to_target_files b/tools/releasetools/add_img_to_target_files
new file mode 120000
index 0000000..04323bd
--- /dev/null
+++ b/tools/releasetools/add_img_to_target_files
@@ -0,0 +1 @@
+add_img_to_target_files.py
\ No newline at end of file
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
new file mode 100755
index 0000000..bf217e0
--- /dev/null
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -0,0 +1,268 @@
+#!/usr/bin/env python
+#
+# 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.
+
+"""
+Given a target-files zipfile that does not contain images (ie, does
+not have an IMAGES/ top-level subdirectory), produce the images and
+add them to the zipfile.
+
+Usage:  add_img_to_target_files target_files
+"""
+
+import sys
+
+if sys.hexversion < 0x02070000:
+  print >> sys.stderr, "Python 2.7 or newer is required."
+  sys.exit(1)
+
+import errno
+import os
+import re
+import shutil
+import subprocess
+import tempfile
+import zipfile
+
+# missing in Python 2.4 and before
+if not hasattr(os, "SEEK_SET"):
+  os.SEEK_SET = 0
+
+import build_image
+import common
+
+OPTIONS = common.OPTIONS
+
+
+def AddSystem(output_zip, prefix="IMAGES/"):
+  """Turn the contents of SYSTEM into a system image and store it in
+  output_zip."""
+  block_list = common.MakeTempFile(prefix="system-blocklist-", suffix=".map")
+  imgname = BuildSystem(OPTIONS.input_tmp, OPTIONS.info_dict,
+                        block_list=block_list)
+  with open(imgname, "rb") as f:
+    common.ZipWriteStr(output_zip, prefix + "system.img", f.read())
+  with open(block_list, "rb") as f:
+    common.ZipWriteStr(output_zip, prefix + "system.map", f.read())
+
+
+def BuildSystem(input_dir, info_dict, block_list=None):
+  """Build the (sparse) system image and return the name of a temp
+  file containing it."""
+  return CreateImage(input_dir, info_dict, "system", block_list=block_list)
+
+
+def AddVendor(output_zip, prefix="IMAGES/"):
+  """Turn the contents of VENDOR into a vendor image and store in it
+  output_zip."""
+  block_list = common.MakeTempFile(prefix="vendor-blocklist-", suffix=".map")
+  imgname = BuildVendor(OPTIONS.input_tmp, OPTIONS.info_dict,
+                     block_list=block_list)
+  with open(imgname, "rb") as f:
+    common.ZipWriteStr(output_zip, prefix + "vendor.img", f.read())
+  with open(block_list, "rb") as f:
+    common.ZipWriteStr(output_zip, prefix + "vendor.map", f.read())
+
+
+def BuildVendor(input_dir, info_dict, block_list=None):
+  """Build the (sparse) vendor image and return the name of a temp
+  file containing it."""
+  return CreateImage(input_dir, info_dict, "vendor", block_list=block_list)
+
+
+def CreateImage(input_dir, info_dict, what, block_list=None):
+  print "creating " + what + ".img..."
+
+  img = common.MakeTempFile(prefix=what + "-", suffix=".img")
+
+  # The name of the directory it is making an image out of matters to
+  # mkyaffs2image.  It wants "system" but we have a directory named
+  # "SYSTEM", so create a symlink.
+  try:
+    os.symlink(os.path.join(input_dir, what.upper()),
+               os.path.join(input_dir, what))
+  except OSError, e:
+      # bogus error on my mac version?
+      #   File "./build/tools/releasetools/img_from_target_files", line 86, in AddSystem
+      #     os.path.join(OPTIONS.input_tmp, "system"))
+      # OSError: [Errno 17] File exists
+    if (e.errno == errno.EEXIST):
+      pass
+
+  image_props = build_image.ImagePropFromGlobalDict(info_dict, what)
+  fstab = info_dict["fstab"]
+  if fstab:
+    image_props["fs_type" ] = fstab["/" + what].fs_type
+
+  if what == "system":
+    fs_config_prefix = ""
+  else:
+    fs_config_prefix = what + "_"
+
+  fs_config = os.path.join(
+      input_dir, "META/" + fs_config_prefix + "filesystem_config.txt")
+  if not os.path.exists(fs_config): fs_config = None
+
+  fc_config = os.path.join(input_dir, "BOOT/RAMDISK/file_contexts")
+  if not os.path.exists(fc_config): fc_config = None
+
+  succ = build_image.BuildImage(os.path.join(input_dir, what),
+                                image_props, img,
+                                fs_config=fs_config,
+                                fc_config=fc_config,
+                                block_list=block_list)
+  assert succ, "build " + what + ".img image failed"
+
+  return img
+
+
+def AddUserdata(output_zip, prefix="IMAGES/"):
+  """Create an empty userdata image and store it in output_zip."""
+
+  image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict,
+                                                    "data")
+  # We only allow yaffs to have a 0/missing partition_size.
+  # Extfs, f2fs must have a size. Skip userdata.img if no size.
+  if (not image_props.get("fs_type", "").startswith("yaffs") and
+      not image_props.get("partition_size")):
+    return
+
+  print "creating userdata.img..."
+
+  # The name of the directory it is making an image out of matters to
+  # mkyaffs2image.  So we create a temp dir, and within it we create an
+  # empty dir named "data", and build the image from that.
+  temp_dir = tempfile.mkdtemp()
+  user_dir = os.path.join(temp_dir, "data")
+  os.mkdir(user_dir)
+  img = tempfile.NamedTemporaryFile()
+
+  fstab = OPTIONS.info_dict["fstab"]
+  if fstab:
+    image_props["fs_type" ] = fstab["/data"].fs_type
+  succ = build_image.BuildImage(user_dir, image_props, img.name)
+  assert succ, "build userdata.img image failed"
+
+  common.CheckSize(img.name, "userdata.img", OPTIONS.info_dict)
+  output_zip.write(img.name, prefix + "userdata.img")
+  img.close()
+  os.rmdir(user_dir)
+  os.rmdir(temp_dir)
+
+
+def AddCache(output_zip, prefix="IMAGES/"):
+  """Create an empty cache image and store it in output_zip."""
+
+  image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict,
+                                                    "cache")
+  # The build system has to explicitly request for cache.img.
+  if "fs_type" not in image_props:
+    return
+
+  print "creating cache.img..."
+
+  # The name of the directory it is making an image out of matters to
+  # mkyaffs2image.  So we create a temp dir, and within it we create an
+  # empty dir named "cache", and build the image from that.
+  temp_dir = tempfile.mkdtemp()
+  user_dir = os.path.join(temp_dir, "cache")
+  os.mkdir(user_dir)
+  img = tempfile.NamedTemporaryFile()
+
+  fstab = OPTIONS.info_dict["fstab"]
+  if fstab:
+    image_props["fs_type" ] = fstab["/cache"].fs_type
+  succ = build_image.BuildImage(user_dir, image_props, img.name)
+  assert succ, "build cache.img image failed"
+
+  common.CheckSize(img.name, "cache.img", OPTIONS.info_dict)
+  output_zip.write(img.name, prefix + "cache.img")
+  img.close()
+  os.rmdir(user_dir)
+  os.rmdir(temp_dir)
+
+
+def AddImagesToTargetFiles(filename):
+  OPTIONS.input_tmp, input_zip = common.UnzipTemp(filename)
+
+  for n in input_zip.namelist():
+    if n.startswith("IMAGES/"):
+      print "target_files appears to already contain images."
+      sys.exit(1)
+
+  try:
+    input_zip.getinfo("VENDOR/")
+    has_vendor = True
+  except KeyError:
+    has_vendor = False
+
+  OPTIONS.info_dict = common.LoadInfoDict(input_zip)
+  if "selinux_fc" in OPTIONS.info_dict:
+    OPTIONS.info_dict["selinux_fc"] = os.path.join(
+        OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")
+
+  input_zip.close()
+  output_zip = zipfile.ZipFile(filename, "a",
+                               compression=zipfile.ZIP_DEFLATED)
+
+  def banner(s):
+    print "\n\n++++ " + s + " ++++\n\n"
+
+  banner("boot")
+  boot_image = common.GetBootableImage(
+      "IMAGES/boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
+  if boot_image:
+    boot_image.AddToZip(output_zip)
+
+  banner("recovery")
+  recovery_image = common.GetBootableImage(
+      "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
+  if recovery_image:
+    recovery_image.AddToZip(output_zip)
+
+  banner("system")
+  AddSystem(output_zip)
+  if has_vendor:
+    banner("vendor")
+    AddVendor(output_zip)
+  banner("userdata")
+  AddUserdata(output_zip)
+  banner("cache")
+  AddCache(output_zip)
+
+  output_zip.close()
+
+
+def main(argv):
+  args = common.ParseOptions(argv, __doc__)
+
+  if len(args) != 1:
+    common.Usage(__doc__)
+    sys.exit(1)
+
+  AddImagesToTargetFiles(args[0])
+  print "done."
+
+if __name__ == '__main__':
+  try:
+    common.CloseInheritedPipes()
+    main(sys.argv[1:])
+  except common.ExternalError, e:
+    print
+    print "   ERROR: %s" % (e,)
+    print
+    sys.exit(1)
+  finally:
+    common.Cleanup()
diff --git a/tools/releasetools/blockimgdiff.py b/tools/releasetools/blockimgdiff.py
new file mode 100644
index 0000000..8b179d5
--- /dev/null
+++ b/tools/releasetools/blockimgdiff.py
@@ -0,0 +1,817 @@
+# 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.
+
+from __future__ import print_function
+
+from collections import deque, OrderedDict
+from hashlib import sha1
+import heapq
+import itertools
+import multiprocessing
+import os
+import pprint
+import re
+import subprocess
+import sys
+import threading
+import tempfile
+
+from rangelib import *
+
+__all__ = ["EmptyImage", "DataImage", "BlockImageDiff"]
+
+def compute_patch(src, tgt, imgdiff=False):
+  srcfd, srcfile = tempfile.mkstemp(prefix="src-")
+  tgtfd, tgtfile = tempfile.mkstemp(prefix="tgt-")
+  patchfd, patchfile = tempfile.mkstemp(prefix="patch-")
+  os.close(patchfd)
+
+  try:
+    with os.fdopen(srcfd, "wb") as f_src:
+      for p in src:
+        f_src.write(p)
+
+    with os.fdopen(tgtfd, "wb") as f_tgt:
+      for p in tgt:
+        f_tgt.write(p)
+    try:
+      os.unlink(patchfile)
+    except OSError:
+      pass
+    if imgdiff:
+      p = subprocess.call(["imgdiff", "-z", srcfile, tgtfile, patchfile],
+                          stdout=open("/dev/null", "a"),
+                          stderr=subprocess.STDOUT)
+    else:
+      p = subprocess.call(["bsdiff", srcfile, tgtfile, patchfile])
+
+    if p:
+      raise ValueError("diff failed: " + str(p))
+
+    with open(patchfile, "rb") as f:
+      return f.read()
+  finally:
+    try:
+      os.unlink(srcfile)
+      os.unlink(tgtfile)
+      os.unlink(patchfile)
+    except OSError:
+      pass
+
+class EmptyImage(object):
+  """A zero-length image."""
+  blocksize = 4096
+  care_map = RangeSet()
+  total_blocks = 0
+  file_map = {}
+  def ReadRangeSet(self, ranges):
+    return ()
+  def TotalSha1(self):
+    return sha1().hexdigest()
+
+
+class DataImage(object):
+  """An image wrapped around a single string of data."""
+
+  def __init__(self, data, trim=False, pad=False):
+    self.data = data
+    self.blocksize = 4096
+
+    assert not (trim and pad)
+
+    partial = len(self.data) % self.blocksize
+    if partial > 0:
+      if trim:
+        self.data = self.data[:-partial]
+      elif pad:
+        self.data += '\0' * (self.blocksize - partial)
+      else:
+        raise ValueError(("data for DataImage must be multiple of %d bytes "
+                          "unless trim or pad is specified") %
+                         (self.blocksize,))
+
+    assert len(self.data) % self.blocksize == 0
+
+    self.total_blocks = len(self.data) / self.blocksize
+    self.care_map = RangeSet(data=(0, self.total_blocks))
+
+    zero_blocks = []
+    nonzero_blocks = []
+    reference = '\0' * self.blocksize
+
+    for i in range(self.total_blocks):
+      d = self.data[i*self.blocksize : (i+1)*self.blocksize]
+      if d == reference:
+        zero_blocks.append(i)
+        zero_blocks.append(i+1)
+      else:
+        nonzero_blocks.append(i)
+        nonzero_blocks.append(i+1)
+
+    self.file_map = {"__ZERO": RangeSet(zero_blocks),
+                     "__NONZERO": RangeSet(nonzero_blocks)}
+
+  def ReadRangeSet(self, ranges):
+    return [self.data[s*self.blocksize:e*self.blocksize] for (s, e) in ranges]
+
+  def TotalSha1(self):
+    if not hasattr(self, "sha1"):
+      self.sha1 = sha1(self.data).hexdigest()
+    return self.sha1
+
+
+class Transfer(object):
+  def __init__(self, tgt_name, src_name, tgt_ranges, src_ranges, style, by_id):
+    self.tgt_name = tgt_name
+    self.src_name = src_name
+    self.tgt_ranges = tgt_ranges
+    self.src_ranges = src_ranges
+    self.style = style
+    self.intact = (getattr(tgt_ranges, "monotonic", False) and
+                   getattr(src_ranges, "monotonic", False))
+    self.goes_before = {}
+    self.goes_after = {}
+
+    self.stash_before = []
+    self.use_stash = []
+
+    self.id = len(by_id)
+    by_id.append(self)
+
+  def NetStashChange(self):
+    return (sum(sr.size() for (_, sr) in self.stash_before) -
+            sum(sr.size() for (_, sr) in self.use_stash))
+
+  def __str__(self):
+    return (str(self.id) + ": <" + str(self.src_ranges) + " " + self.style +
+            " to " + str(self.tgt_ranges) + ">")
+
+
+# BlockImageDiff works on two image objects.  An image object is
+# anything that provides the following attributes:
+#
+#    blocksize: the size in bytes of a block, currently must be 4096.
+#
+#    total_blocks: the total size of the partition/image, in blocks.
+#
+#    care_map: a RangeSet containing which blocks (in the range [0,
+#      total_blocks) we actually care about; i.e. which blocks contain
+#      data.
+#
+#    file_map: a dict that partitions the blocks contained in care_map
+#      into smaller domains that are useful for doing diffs on.
+#      (Typically a domain is a file, and the key in file_map is the
+#      pathname.)
+#
+#    ReadRangeSet(): a function that takes a RangeSet and returns the
+#      data contained in the image blocks of that RangeSet.  The data
+#      is returned as a list or tuple of strings; concatenating the
+#      elements together should produce the requested data.
+#      Implementations are free to break up the data into list/tuple
+#      elements in any way that is convenient.
+#
+#    TotalSha1(): a function that returns (as a hex string) the SHA-1
+#      hash of all the data in the image (ie, all the blocks in the
+#      care_map)
+#
+# When creating a BlockImageDiff, the src image may be None, in which
+# case the list of transfers produced will never read from the
+# original image.
+
+class BlockImageDiff(object):
+  def __init__(self, tgt, src=None, threads=None, version=2):
+    if threads is None:
+      threads = multiprocessing.cpu_count() // 2
+      if threads == 0: threads = 1
+    self.threads = threads
+    self.version = version
+
+    assert version in (1, 2)
+
+    self.tgt = tgt
+    if src is None:
+      src = EmptyImage()
+    self.src = src
+
+    # The updater code that installs the patch always uses 4k blocks.
+    assert tgt.blocksize == 4096
+    assert src.blocksize == 4096
+
+    # The range sets in each filemap should comprise a partition of
+    # the care map.
+    self.AssertPartition(src.care_map, src.file_map.values())
+    self.AssertPartition(tgt.care_map, tgt.file_map.values())
+
+  def Compute(self, prefix):
+    # When looking for a source file to use as the diff input for a
+    # target file, we try:
+    #   1) an exact path match if available, otherwise
+    #   2) a exact basename match if available, otherwise
+    #   3) a basename match after all runs of digits are replaced by
+    #      "#" if available, otherwise
+    #   4) we have no source for this target.
+    self.AbbreviateSourceNames()
+    self.FindTransfers()
+
+    # Find the ordering dependencies among transfers (this is O(n^2)
+    # in the number of transfers).
+    self.GenerateDigraph()
+    # Find a sequence of transfers that satisfies as many ordering
+    # dependencies as possible (heuristically).
+    self.FindVertexSequence()
+    # Fix up the ordering dependencies that the sequence didn't
+    # satisfy.
+    if self.version == 1:
+      self.RemoveBackwardEdges()
+    else:
+      self.ReverseBackwardEdges()
+      self.ImproveVertexSequence()
+
+    # Double-check our work.
+    self.AssertSequenceGood()
+
+    self.ComputePatches(prefix)
+    self.WriteTransfers(prefix)
+
+  def WriteTransfers(self, prefix):
+    out = []
+
+    total = 0
+    performs_read = False
+
+    stashes = {}
+    stashed_blocks = 0
+    max_stashed_blocks = 0
+
+    free_stash_ids = []
+    next_stash_id = 0
+
+    for xf in self.transfers:
+
+      if self.version < 2:
+        assert not xf.stash_before
+        assert not xf.use_stash
+
+      for s, sr in xf.stash_before:
+        assert s not in stashes
+        if free_stash_ids:
+          sid = heapq.heappop(free_stash_ids)
+        else:
+          sid = next_stash_id
+          next_stash_id += 1
+        stashes[s] = sid
+        stashed_blocks += sr.size()
+        out.append("stash %d %s\n" % (sid, sr.to_string_raw()))
+
+      if stashed_blocks > max_stashed_blocks:
+        max_stashed_blocks = stashed_blocks
+
+      if self.version == 1:
+        src_string = xf.src_ranges.to_string_raw()
+      elif self.version == 2:
+
+        #   <# blocks> <src ranges>
+        #     OR
+        #   <# blocks> <src ranges> <src locs> <stash refs...>
+        #     OR
+        #   <# blocks> - <stash refs...>
+
+        size = xf.src_ranges.size()
+        src_string = [str(size)]
+
+        unstashed_src_ranges = xf.src_ranges
+        mapped_stashes = []
+        for s, sr in xf.use_stash:
+          sid = stashes.pop(s)
+          stashed_blocks -= sr.size()
+          unstashed_src_ranges = unstashed_src_ranges.subtract(sr)
+          sr = xf.src_ranges.map_within(sr)
+          mapped_stashes.append(sr)
+          src_string.append("%d:%s" % (sid, sr.to_string_raw()))
+          heapq.heappush(free_stash_ids, sid)
+
+        if unstashed_src_ranges:
+          src_string.insert(1, unstashed_src_ranges.to_string_raw())
+          if xf.use_stash:
+            mapped_unstashed = xf.src_ranges.map_within(unstashed_src_ranges)
+            src_string.insert(2, mapped_unstashed.to_string_raw())
+            mapped_stashes.append(mapped_unstashed)
+            self.AssertPartition(RangeSet(data=(0, size)), mapped_stashes)
+        else:
+          src_string.insert(1, "-")
+          self.AssertPartition(RangeSet(data=(0, size)), mapped_stashes)
+
+        src_string = " ".join(src_string)
+
+      # both versions:
+      #   zero <rangeset>
+      #   new <rangeset>
+      #   erase <rangeset>
+      #
+      # version 1:
+      #   bsdiff patchstart patchlen <src rangeset> <tgt rangeset>
+      #   imgdiff patchstart patchlen <src rangeset> <tgt rangeset>
+      #   move <src rangeset> <tgt rangeset>
+      #
+      # version 2:
+      #   bsdiff patchstart patchlen <tgt rangeset> <src_string>
+      #   imgdiff patchstart patchlen <tgt rangeset> <src_string>
+      #   move <tgt rangeset> <src_string>
+
+      tgt_size = xf.tgt_ranges.size()
+
+      if xf.style == "new":
+        assert xf.tgt_ranges
+        out.append("%s %s\n" % (xf.style, xf.tgt_ranges.to_string_raw()))
+        total += tgt_size
+      elif xf.style == "move":
+        performs_read = True
+        assert xf.tgt_ranges
+        assert xf.src_ranges.size() == tgt_size
+        if xf.src_ranges != xf.tgt_ranges:
+          if self.version == 1:
+            out.append("%s %s %s\n" % (
+                xf.style,
+                xf.src_ranges.to_string_raw(), xf.tgt_ranges.to_string_raw()))
+          elif self.version == 2:
+            out.append("%s %s %s\n" % (
+                xf.style,
+                xf.tgt_ranges.to_string_raw(), src_string))
+          total += tgt_size
+      elif xf.style in ("bsdiff", "imgdiff"):
+        performs_read = True
+        assert xf.tgt_ranges
+        assert xf.src_ranges
+        if self.version == 1:
+          out.append("%s %d %d %s %s\n" % (
+              xf.style, xf.patch_start, xf.patch_len,
+              xf.src_ranges.to_string_raw(), xf.tgt_ranges.to_string_raw()))
+        elif self.version == 2:
+          out.append("%s %d %d %s %s\n" % (
+              xf.style, xf.patch_start, xf.patch_len,
+              xf.tgt_ranges.to_string_raw(), src_string))
+        total += tgt_size
+      elif xf.style == "zero":
+        assert xf.tgt_ranges
+        to_zero = xf.tgt_ranges.subtract(xf.src_ranges)
+        if to_zero:
+          out.append("%s %s\n" % (xf.style, to_zero.to_string_raw()))
+          total += to_zero.size()
+      else:
+        raise ValueError, "unknown transfer style '%s'\n" % (xf.style,)
+
+
+      # sanity check: abort if we're going to need more than 512 MB if
+      # stash space
+      assert max_stashed_blocks * self.tgt.blocksize < (512 << 20)
+
+    all_tgt = RangeSet(data=(0, self.tgt.total_blocks))
+    if performs_read:
+      # if some of the original data is used, then at the end we'll
+      # erase all the blocks on the partition that don't contain data
+      # in the new image.
+      new_dontcare = all_tgt.subtract(self.tgt.care_map)
+      if new_dontcare:
+        out.append("erase %s\n" % (new_dontcare.to_string_raw(),))
+    else:
+      # if nothing is read (ie, this is a full OTA), then we can start
+      # by erasing the entire partition.
+      out.insert(0, "erase %s\n" % (all_tgt.to_string_raw(),))
+
+    out.insert(0, "%d\n" % (self.version,))   # format version number
+    out.insert(1, str(total) + "\n")
+    if self.version >= 2:
+      # version 2 only: after the total block count, we give the number
+      # of stash slots needed, and the maximum size needed (in blocks)
+      out.insert(2, str(next_stash_id) + "\n")
+      out.insert(3, str(max_stashed_blocks) + "\n")
+
+    with open(prefix + ".transfer.list", "wb") as f:
+      for i in out:
+        f.write(i)
+
+    if self.version >= 2:
+      print("max stashed blocks: %d  (%d bytes)\n" % (
+          max_stashed_blocks, max_stashed_blocks * self.tgt.blocksize))
+
+  def ComputePatches(self, prefix):
+    print("Reticulating splines...")
+    diff_q = []
+    patch_num = 0
+    with open(prefix + ".new.dat", "wb") as new_f:
+      for xf in self.transfers:
+        if xf.style == "zero":
+          pass
+        elif xf.style == "new":
+          for piece in self.tgt.ReadRangeSet(xf.tgt_ranges):
+            new_f.write(piece)
+        elif xf.style == "diff":
+          src = self.src.ReadRangeSet(xf.src_ranges)
+          tgt = self.tgt.ReadRangeSet(xf.tgt_ranges)
+
+          # We can't compare src and tgt directly because they may have
+          # the same content but be broken up into blocks differently, eg:
+          #
+          #    ["he", "llo"]  vs  ["h", "ello"]
+          #
+          # We want those to compare equal, ideally without having to
+          # actually concatenate the strings (these may be tens of
+          # megabytes).
+
+          src_sha1 = sha1()
+          for p in src:
+            src_sha1.update(p)
+          tgt_sha1 = sha1()
+          tgt_size = 0
+          for p in tgt:
+            tgt_sha1.update(p)
+            tgt_size += len(p)
+
+          if src_sha1.digest() == tgt_sha1.digest():
+            # These are identical; we don't need to generate a patch,
+            # just issue copy commands on the device.
+            xf.style = "move"
+          else:
+            # For files in zip format (eg, APKs, JARs, etc.) we would
+            # like to use imgdiff -z if possible (because it usually
+            # produces significantly smaller patches than bsdiff).
+            # This is permissible if:
+            #
+            #  - the source and target files are monotonic (ie, the
+            #    data is stored with blocks in increasing order), and
+            #  - we haven't removed any blocks from the source set.
+            #
+            # If these conditions are satisfied then appending all the
+            # blocks in the set together in order will produce a valid
+            # zip file (plus possibly extra zeros in the last block),
+            # which is what imgdiff needs to operate.  (imgdiff is
+            # fine with extra zeros at the end of the file.)
+            imgdiff = (xf.intact and
+                       xf.tgt_name.split(".")[-1].lower()
+                       in ("apk", "jar", "zip"))
+            xf.style = "imgdiff" if imgdiff else "bsdiff"
+            diff_q.append((tgt_size, src, tgt, xf, patch_num))
+            patch_num += 1
+
+        else:
+          assert False, "unknown style " + xf.style
+
+    if diff_q:
+      if self.threads > 1:
+        print("Computing patches (using %d threads)..." % (self.threads,))
+      else:
+        print("Computing patches...")
+      diff_q.sort()
+
+      patches = [None] * patch_num
+
+      lock = threading.Lock()
+      def diff_worker():
+        while True:
+          with lock:
+            if not diff_q: return
+            tgt_size, src, tgt, xf, patchnum = diff_q.pop()
+          patch = compute_patch(src, tgt, imgdiff=(xf.style == "imgdiff"))
+          size = len(patch)
+          with lock:
+            patches[patchnum] = (patch, xf)
+            print("%10d %10d (%6.2f%%) %7s %s" % (
+                size, tgt_size, size * 100.0 / tgt_size, xf.style,
+                xf.tgt_name if xf.tgt_name == xf.src_name else (
+                    xf.tgt_name + " (from " + xf.src_name + ")")))
+
+      threads = [threading.Thread(target=diff_worker)
+                 for i in range(self.threads)]
+      for th in threads:
+        th.start()
+      while threads:
+        threads.pop().join()
+    else:
+      patches = []
+
+    p = 0
+    with open(prefix + ".patch.dat", "wb") as patch_f:
+      for patch, xf in patches:
+        xf.patch_start = p
+        xf.patch_len = len(patch)
+        patch_f.write(patch)
+        p += len(patch)
+
+  def AssertSequenceGood(self):
+    # Simulate the sequences of transfers we will output, and check that:
+    # - we never read a block after writing it, and
+    # - we write every block we care about exactly once.
+
+    # Start with no blocks having been touched yet.
+    touched = RangeSet()
+
+    # Imagine processing the transfers in order.
+    for xf in self.transfers:
+      # Check that the input blocks for this transfer haven't yet been touched.
+
+      x = xf.src_ranges
+      if self.version >= 2:
+        for _, sr in xf.use_stash:
+          x = x.subtract(sr)
+
+      assert not touched.overlaps(x)
+      # Check that the output blocks for this transfer haven't yet been touched.
+      assert not touched.overlaps(xf.tgt_ranges)
+      # Touch all the blocks written by this transfer.
+      touched = touched.union(xf.tgt_ranges)
+
+    # Check that we've written every target block.
+    assert touched == self.tgt.care_map
+
+  def ImproveVertexSequence(self):
+    print("Improving vertex order...")
+
+    # At this point our digraph is acyclic; we reversed any edges that
+    # were backwards in the heuristically-generated sequence.  The
+    # previously-generated order is still acceptable, but we hope to
+    # find a better order that needs less memory for stashed data.
+    # Now we do a topological sort to generate a new vertex order,
+    # using a greedy algorithm to choose which vertex goes next
+    # whenever we have a choice.
+
+    # Make a copy of the edge set; this copy will get destroyed by the
+    # algorithm.
+    for xf in self.transfers:
+      xf.incoming = xf.goes_after.copy()
+      xf.outgoing = xf.goes_before.copy()
+
+    L = []   # the new vertex order
+
+    # S is the set of sources in the remaining graph; we always choose
+    # the one that leaves the least amount of stashed data after it's
+    # executed.
+    S = [(u.NetStashChange(), u.order, u) for u in self.transfers
+         if not u.incoming]
+    heapq.heapify(S)
+
+    while S:
+      _, _, xf = heapq.heappop(S)
+      L.append(xf)
+      for u in xf.outgoing:
+        del u.incoming[xf]
+        if not u.incoming:
+          heapq.heappush(S, (u.NetStashChange(), u.order, u))
+
+    # if this fails then our graph had a cycle.
+    assert len(L) == len(self.transfers)
+
+    self.transfers = L
+    for i, xf in enumerate(L):
+      xf.order = i
+
+  def RemoveBackwardEdges(self):
+    print("Removing backward edges...")
+    in_order = 0
+    out_of_order = 0
+    lost_source = 0
+
+    for xf in self.transfers:
+      lost = 0
+      size = xf.src_ranges.size()
+      for u in xf.goes_before:
+        # xf should go before u
+        if xf.order < u.order:
+          # it does, hurray!
+          in_order += 1
+        else:
+          # it doesn't, boo.  trim the blocks that u writes from xf's
+          # source, so that xf can go after u.
+          out_of_order += 1
+          assert xf.src_ranges.overlaps(u.tgt_ranges)
+          xf.src_ranges = xf.src_ranges.subtract(u.tgt_ranges)
+          xf.intact = False
+
+      if xf.style == "diff" and not xf.src_ranges:
+        # nothing left to diff from; treat as new data
+        xf.style = "new"
+
+      lost = size - xf.src_ranges.size()
+      lost_source += lost
+
+    print(("  %d/%d dependencies (%.2f%%) were violated; "
+           "%d source blocks removed.") %
+          (out_of_order, in_order + out_of_order,
+           (out_of_order * 100.0 / (in_order + out_of_order))
+           if (in_order + out_of_order) else 0.0,
+           lost_source))
+
+  def ReverseBackwardEdges(self):
+    print("Reversing backward edges...")
+    in_order = 0
+    out_of_order = 0
+    stashes = 0
+    stash_size = 0
+
+    for xf in self.transfers:
+      lost = 0
+      size = xf.src_ranges.size()
+      for u in xf.goes_before.copy():
+        # xf should go before u
+        if xf.order < u.order:
+          # it does, hurray!
+          in_order += 1
+        else:
+          # it doesn't, boo.  modify u to stash the blocks that it
+          # writes that xf wants to read, and then require u to go
+          # before xf.
+          out_of_order += 1
+
+          overlap = xf.src_ranges.intersect(u.tgt_ranges)
+          assert overlap
+
+          u.stash_before.append((stashes, overlap))
+          xf.use_stash.append((stashes, overlap))
+          stashes += 1
+          stash_size += overlap.size()
+
+          # reverse the edge direction; now xf must go after u
+          del xf.goes_before[u]
+          del u.goes_after[xf]
+          xf.goes_after[u] = None    # value doesn't matter
+          u.goes_before[xf] = None
+
+    print(("  %d/%d dependencies (%.2f%%) were violated; "
+           "%d source blocks stashed.") %
+          (out_of_order, in_order + out_of_order,
+           (out_of_order * 100.0 / (in_order + out_of_order))
+           if (in_order + out_of_order) else 0.0,
+           stash_size))
+
+  def FindVertexSequence(self):
+    print("Finding vertex sequence...")
+
+    # This is based on "A Fast & Effective Heuristic for the Feedback
+    # Arc Set Problem" by P. Eades, X. Lin, and W.F. Smyth.  Think of
+    # it as starting with the digraph G and moving all the vertices to
+    # be on a horizontal line in some order, trying to minimize the
+    # number of edges that end up pointing to the left.  Left-pointing
+    # edges will get removed to turn the digraph into a DAG.  In this
+    # case each edge has a weight which is the number of source blocks
+    # we'll lose if that edge is removed; we try to minimize the total
+    # weight rather than just the number of edges.
+
+    # Make a copy of the edge set; this copy will get destroyed by the
+    # algorithm.
+    for xf in self.transfers:
+      xf.incoming = xf.goes_after.copy()
+      xf.outgoing = xf.goes_before.copy()
+
+    # We use an OrderedDict instead of just a set so that the output
+    # is repeatable; otherwise it would depend on the hash values of
+    # the transfer objects.
+    G = OrderedDict()
+    for xf in self.transfers:
+      G[xf] = None
+    s1 = deque()  # the left side of the sequence, built from left to right
+    s2 = deque()  # the right side of the sequence, built from right to left
+
+    while G:
+
+      # Put all sinks at the end of the sequence.
+      while True:
+        sinks = [u for u in G if not u.outgoing]
+        if not sinks: break
+        for u in sinks:
+          s2.appendleft(u)
+          del G[u]
+          for iu in u.incoming:
+            del iu.outgoing[u]
+
+      # Put all the sources at the beginning of the sequence.
+      while True:
+        sources = [u for u in G if not u.incoming]
+        if not sources: break
+        for u in sources:
+          s1.append(u)
+          del G[u]
+          for iu in u.outgoing:
+            del iu.incoming[u]
+
+      if not G: break
+
+      # Find the "best" vertex to put next.  "Best" is the one that
+      # maximizes the net difference in source blocks saved we get by
+      # pretending it's a source rather than a sink.
+
+      max_d = None
+      best_u = None
+      for u in G:
+        d = sum(u.outgoing.values()) - sum(u.incoming.values())
+        if best_u is None or d > max_d:
+          max_d = d
+          best_u = u
+
+      u = best_u
+      s1.append(u)
+      del G[u]
+      for iu in u.outgoing:
+        del iu.incoming[u]
+      for iu in u.incoming:
+        del iu.outgoing[u]
+
+    # Now record the sequence in the 'order' field of each transfer,
+    # and by rearranging self.transfers to be in the chosen sequence.
+
+    new_transfers = []
+    for x in itertools.chain(s1, s2):
+      x.order = len(new_transfers)
+      new_transfers.append(x)
+      del x.incoming
+      del x.outgoing
+
+    self.transfers = new_transfers
+
+  def GenerateDigraph(self):
+    print("Generating digraph...")
+    for a in self.transfers:
+      for b in self.transfers:
+        if a is b: continue
+
+        # If the blocks written by A are read by B, then B needs to go before A.
+        i = a.tgt_ranges.intersect(b.src_ranges)
+        if i:
+          if b.src_name == "__ZERO":
+            # the cost of removing source blocks for the __ZERO domain
+            # is (nearly) zero.
+            size = 0
+          else:
+            size = i.size()
+          b.goes_before[a] = size
+          a.goes_after[b] = size
+
+  def FindTransfers(self):
+    self.transfers = []
+    empty = RangeSet()
+    for tgt_fn, tgt_ranges in self.tgt.file_map.items():
+      if tgt_fn == "__ZERO":
+        # the special "__ZERO" domain is all the blocks not contained
+        # in any file and that are filled with zeros.  We have a
+        # special transfer style for zero blocks.
+        src_ranges = self.src.file_map.get("__ZERO", empty)
+        Transfer(tgt_fn, "__ZERO", tgt_ranges, src_ranges,
+                 "zero", self.transfers)
+        continue
+
+      elif tgt_fn in self.src.file_map:
+        # Look for an exact pathname match in the source.
+        Transfer(tgt_fn, tgt_fn, tgt_ranges, self.src.file_map[tgt_fn],
+                 "diff", self.transfers)
+        continue
+
+      b = os.path.basename(tgt_fn)
+      if b in self.src_basenames:
+        # Look for an exact basename match in the source.
+        src_fn = self.src_basenames[b]
+        Transfer(tgt_fn, src_fn, tgt_ranges, self.src.file_map[src_fn],
+                 "diff", self.transfers)
+        continue
+
+      b = re.sub("[0-9]+", "#", b)
+      if b in self.src_numpatterns:
+        # Look for a 'number pattern' match (a basename match after
+        # all runs of digits are replaced by "#").  (This is useful
+        # for .so files that contain version numbers in the filename
+        # that get bumped.)
+        src_fn = self.src_numpatterns[b]
+        Transfer(tgt_fn, src_fn, tgt_ranges, self.src.file_map[src_fn],
+                 "diff", self.transfers)
+        continue
+
+      Transfer(tgt_fn, None, tgt_ranges, empty, "new", self.transfers)
+
+  def AbbreviateSourceNames(self):
+    self.src_basenames = {}
+    self.src_numpatterns = {}
+
+    for k in self.src.file_map.keys():
+      b = os.path.basename(k)
+      self.src_basenames[b] = k
+      b = re.sub("[0-9]+", "#", b)
+      self.src_numpatterns[b] = k
+
+  @staticmethod
+  def AssertPartition(total, seq):
+    """Assert that all the RangeSets in 'seq' form a partition of the
+    'total' RangeSet (ie, they are nonintersecting and their union
+    equals 'total')."""
+    so_far = RangeSet()
+    for i in seq:
+      assert not so_far.overlaps(i)
+      so_far = so_far.union(i)
+    assert so_far == total
diff --git a/tools/releasetools/build_image.py b/tools/releasetools/build_image.py
index f8f2ada..a010e84 100755
--- a/tools/releasetools/build_image.py
+++ b/tools/releasetools/build_image.py
@@ -24,6 +24,11 @@
 import os.path
 import subprocess
 import sys
+import commands
+import shutil
+import tempfile
+
+FIXED_SALT = "aee087a5be3b982978c923f566a94613496b417f2af592639bc80d141e34dfe7"
 
 def RunCommand(cmd):
   """ Echo and run the given command
@@ -38,13 +43,176 @@
   p.communicate()
   return p.returncode
 
-def BuildImage(in_dir, prop_dict, out_file):
+def GetVerityTreeSize(partition_size):
+  cmd = "build_verity_tree -s %d"
+  cmd %= partition_size
+  status, output = commands.getstatusoutput(cmd)
+  if status:
+    print output
+    return False, 0
+  return True, int(output)
+
+def GetVerityMetadataSize(partition_size):
+  cmd = "system/extras/verity/build_verity_metadata.py -s %d"
+  cmd %= partition_size
+  status, output = commands.getstatusoutput(cmd)
+  if status:
+    print output
+    return False, 0
+  return True, int(output)
+
+def AdjustPartitionSizeForVerity(partition_size):
+  """Modifies the provided partition size to account for the verity metadata.
+
+  This information is used to size the created image appropriately.
+  Args:
+    partition_size: the size of the partition to be verified.
+  Returns:
+    The size of the partition adjusted for verity metadata.
+  """
+  success, verity_tree_size = GetVerityTreeSize(partition_size)
+  if not success:
+    return 0;
+  success, verity_metadata_size = GetVerityMetadataSize(partition_size)
+  if not success:
+    return 0
+  return partition_size - verity_tree_size - verity_metadata_size
+
+def BuildVerityTree(sparse_image_path, verity_image_path, prop_dict):
+  cmd = ("build_verity_tree -A %s %s %s" % (FIXED_SALT, sparse_image_path, verity_image_path))
+  print cmd
+  status, output = commands.getstatusoutput(cmd)
+  if status:
+    print "Could not build verity tree! Error: %s" % output
+    return False
+  root, salt = output.split()
+  prop_dict["verity_root_hash"] = root
+  prop_dict["verity_salt"] = salt
+  return True
+
+def BuildVerityMetadata(image_size, verity_metadata_path, root_hash, salt,
+                        block_device, signer_path, key):
+  cmd = ("system/extras/verity/build_verity_metadata.py %s %s %s %s %s %s %s" %
+              (image_size,
+              verity_metadata_path,
+              root_hash,
+              salt,
+              block_device,
+              signer_path,
+              key))
+  print cmd
+  status, output = commands.getstatusoutput(cmd)
+  if status:
+    print "Could not build verity metadata! Error: %s" % output
+    return False
+  return True
+
+def Append2Simg(sparse_image_path, unsparse_image_path, error_message):
+  """Appends the unsparse image to the given sparse image.
+
+  Args:
+    sparse_image_path: the path to the (sparse) image
+    unsparse_image_path: the path to the (unsparse) image
+  Returns:
+    True on success, False on failure.
+  """
+  cmd = "append2simg %s %s"
+  cmd %= (sparse_image_path, unsparse_image_path)
+  print cmd
+  status, output = commands.getstatusoutput(cmd)
+  if status:
+    print "%s: %s" % (error_message, output)
+    return False
+  return True
+
+def BuildVerifiedImage(data_image_path, verity_image_path, verity_metadata_path):
+  if not Append2Simg(data_image_path, verity_metadata_path, "Could not append verity metadata!"):
+    return False
+  if not Append2Simg(data_image_path, verity_image_path, "Could not append verity tree!"):
+    return False
+  return True
+
+def UnsparseImage(sparse_image_path, replace=True):
+  img_dir = os.path.dirname(sparse_image_path)
+  unsparse_image_path = "unsparse_" + os.path.basename(sparse_image_path)
+  unsparse_image_path = os.path.join(img_dir, unsparse_image_path)
+  if os.path.exists(unsparse_image_path):
+    if replace:
+      os.unlink(unsparse_image_path)
+    else:
+      return True, unsparse_image_path
+  inflate_command = ["simg2img", sparse_image_path, unsparse_image_path]
+  exit_code = RunCommand(inflate_command)
+  if exit_code != 0:
+    os.remove(unsparse_image_path)
+    return False, None
+  return True, unsparse_image_path
+
+def MakeVerityEnabledImage(out_file, prop_dict):
+  """Creates an image that is verifiable using dm-verity.
+
+  Args:
+    out_file: the location to write the verifiable image at
+    prop_dict: a dictionary of properties required for image creation and verification
+  Returns:
+    True on success, False otherwise.
+  """
+  # get properties
+  image_size = prop_dict["partition_size"]
+  block_dev = prop_dict["verity_block_device"]
+  signer_key = prop_dict["verity_key"]
+  signer_path = prop_dict["verity_signer_cmd"]
+
+  # make a tempdir
+  tempdir_name = tempfile.mkdtemp(suffix="_verity_images")
+
+  # get partial image paths
+  verity_image_path = os.path.join(tempdir_name, "verity.img")
+  verity_metadata_path = os.path.join(tempdir_name, "verity_metadata.img")
+
+  # build the verity tree and get the root hash and salt
+  if not BuildVerityTree(out_file, verity_image_path, prop_dict):
+    shutil.rmtree(tempdir_name, ignore_errors=True)
+    return False
+
+  # build the metadata blocks
+  root_hash = prop_dict["verity_root_hash"]
+  salt = prop_dict["verity_salt"]
+  if not BuildVerityMetadata(image_size,
+                              verity_metadata_path,
+                              root_hash,
+                              salt,
+                              block_dev,
+                              signer_path,
+                              signer_key):
+    shutil.rmtree(tempdir_name, ignore_errors=True)
+    return False
+
+  # build the full verified image
+  if not BuildVerifiedImage(out_file,
+                            verity_image_path,
+                            verity_metadata_path):
+    shutil.rmtree(tempdir_name, ignore_errors=True)
+    return False
+
+  shutil.rmtree(tempdir_name, ignore_errors=True)
+  return True
+
+def BuildImage(in_dir, prop_dict, out_file,
+               fs_config=None,
+               fc_config=None,
+               block_list=None):
   """Build an image to out_file from in_dir with property prop_dict.
 
   Args:
     in_dir: path of input directory.
     prop_dict: property dictionary.
     out_file: path of the output image file.
+    fs_config: path to the fs_config file (typically
+      META/filesystem_config.txt).  If None then the configuration in
+      the local client will be used.
+    fc_config: path to the SELinux file_contexts file.  If None then
+      the value from prop_dict['selinux_fc'] will be used.
 
   Returns:
     True iff the image is built successfully.
@@ -52,6 +220,18 @@
   build_command = []
   fs_type = prop_dict.get("fs_type", "")
   run_fsck = False
+
+  is_verity_partition = "verity_block_device" in prop_dict
+  verity_supported = prop_dict.get("verity") == "true"
+  # adjust the partition size to make room for the hashes if this is to be verified
+  if verity_supported and is_verity_partition:
+    partition_size = int(prop_dict.get("partition_size"))
+    adjusted_size = AdjustPartitionSizeForVerity(partition_size)
+    if not adjusted_size:
+      return False
+    prop_dict["partition_size"] = str(adjusted_size)
+    prop_dict["original_partition_size"] = str(partition_size)
+
   if fs_type.startswith("ext"):
     build_command = ["mkuserimg.sh"]
     if "extfs_sparse_flag" in prop_dict:
@@ -59,10 +239,20 @@
       run_fsck = True
     build_command.extend([in_dir, out_file, fs_type,
                           prop_dict["mount_point"]])
-    if "partition_size" in prop_dict:
-      build_command.append(prop_dict["partition_size"])
-    if "selinux_fc" in prop_dict:
+    build_command.append(prop_dict["partition_size"])
+    if "timestamp" in prop_dict:
+      build_command.extend(["-T", str(prop_dict["timestamp"])])
+    if fs_config is not None:
+      build_command.extend(["-C", fs_config])
+    if block_list is not None:
+      build_command.extend(["-B", block_list])
+    if fc_config is not None:
+      build_command.append(fc_config)
+    elif "selinux_fc" in prop_dict:
       build_command.append(prop_dict["selinux_fc"])
+  elif fs_type.startswith("f2fs"):
+    build_command = ["mkf2fsuserimg.sh"]
+    build_command.extend([out_file, prop_dict["partition_size"]])
   else:
     build_command = ["mkyaffs2image", "-f"]
     if prop_dict.get("mkyaffs2_extra_flags", None):
@@ -77,14 +267,14 @@
   if exit_code != 0:
     return False
 
+  # create the verified image if this is to be verified
+  if verity_supported and is_verity_partition:
+    if not MakeVerityEnabledImage(out_file, prop_dict):
+      return False
+
   if run_fsck and prop_dict.get("skip_fsck") != "true":
-    # Inflate the sparse image
-    unsparse_image = os.path.join(
-        os.path.dirname(out_file), "unsparse_" + os.path.basename(out_file))
-    inflate_command = ["simg2img", out_file, unsparse_image]
-    exit_code = RunCommand(inflate_command)
-    if exit_code != 0:
-      os.remove(unsparse_image)
+    success, unsparse_image = UnsparseImage(out_file, replace=False)
+    if not success:
       return False
 
     # Run e2fsck on the inflated image file
@@ -104,6 +294,10 @@
     mount_point: such as "system", "data" etc.
   """
   d = {}
+  if "build.prop" in glob_dict:
+    bp = glob_dict["build.prop"]
+    if "ro.build.date.utc" in bp:
+      d["timestamp"] = bp["ro.build.date.utc"]
 
   def copy_prop(src_p, dest_p):
     if src_p in glob_dict:
@@ -114,6 +308,9 @@
       "mkyaffs2_extra_flags",
       "selinux_fc",
       "skip_fsck",
+      "verity",
+      "verity_key",
+      "verity_signer_cmd"
       )
   for p in common_props:
     copy_prop(p, p)
@@ -122,8 +319,11 @@
   if mount_point == "system":
     copy_prop("fs_type", "fs_type")
     copy_prop("system_size", "partition_size")
+    copy_prop("system_verity_block_device", "verity_block_device")
   elif mount_point == "data":
+    # Copy the generic fs type first, override with specific one if available.
     copy_prop("fs_type", "fs_type")
+    copy_prop("userdata_fs_type", "fs_type")
     copy_prop("userdata_size", "partition_size")
   elif mount_point == "cache":
     copy_prop("cache_fs_type", "fs_type")
@@ -131,6 +331,10 @@
   elif mount_point == "vendor":
     copy_prop("vendor_fs_type", "fs_type")
     copy_prop("vendor_size", "partition_size")
+    copy_prop("vendor_verity_block_device", "verity_block_device")
+  elif mount_point == "oem":
+    copy_prop("fs_type", "fs_type")
+    copy_prop("oem_size", "partition_size")
 
   return d
 
@@ -169,6 +373,8 @@
     mount_point = "cache"
   elif image_filename == "vendor.img":
     mount_point = "vendor"
+  elif image_filename == "oem.img":
+    mount_point = "oem"
   else:
     print >> sys.stderr, "error: unknown image file name ", image_filename
     exit(1)
diff --git a/tools/releasetools/check_target_files_signatures b/tools/releasetools/check_target_files_signatures
index 45d30a6..b2f46c1 100755
--- a/tools/releasetools/check_target_files_signatures
+++ b/tools/releasetools/check_target_files_signatures
@@ -41,8 +41,8 @@
 
 import sys
 
-if sys.hexversion < 0x02040000:
-  print >> sys.stderr, "Python 2.4 or newer is required."
+if sys.hexversion < 0x02070000:
+  print >> sys.stderr, "Python 2.7 or newer is required."
   sys.exit(1)
 
 import os
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index b992da3..96075a9 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -29,6 +29,9 @@
 import time
 import zipfile
 
+import blockimgdiff
+from rangelib import *
+
 try:
   from hashlib import sha1 as sha1
 except ImportError:
@@ -40,10 +43,17 @@
 
 class Options(object): pass
 OPTIONS = Options()
-OPTIONS.search_path = "out/host/linux-x86"
+
+DEFAULT_SEARCH_PATH_BY_PLATFORM = {
+    "linux2": "out/host/linux-x86",
+    "darwin": "out/host/darwin-x86",
+    }
+OPTIONS.search_path = DEFAULT_SEARCH_PATH_BY_PLATFORM.get(sys.platform, None)
+
 OPTIONS.signapk_path = "framework/signapk.jar"  # Relative to search_path
 OPTIONS.extra_signapk_args = []
 OPTIONS.java_path = "java"  # Use the one on the path by default.
+OPTIONS.java_args = "-Xmx2048m" # JVM Args
 OPTIONS.public_key_suffix = ".x509.pem"
 OPTIONS.private_key_suffix = ".pk8"
 OPTIONS.verbose = False
@@ -84,17 +94,24 @@
       pass
 
 
-def LoadInfoDict(zip):
+def LoadInfoDict(input):
   """Read and parse the META/misc_info.txt key/value pairs from the
   input target files and return a dict."""
 
+  def read_helper(fn):
+    if isinstance(input, zipfile.ZipFile):
+      return input.read(fn)
+    else:
+      path = os.path.join(input, *fn.split("/"))
+      try:
+        with open(path) as f:
+          return f.read()
+      except IOError, e:
+        if e.errno == errno.ENOENT:
+          raise KeyError(fn)
   d = {}
   try:
-    for line in zip.read("META/misc_info.txt").split("\n"):
-      line = line.strip()
-      if not line or line.startswith("#"): continue
-      k, v = line.split("=", 1)
-      d[k] = v
+    d = LoadDictionaryFromLines(read_helper("META/misc_info.txt").split("\n"))
   except KeyError:
     # ok if misc_info.txt doesn't exist
     pass
@@ -105,20 +122,20 @@
 
   if "mkyaffs2_extra_flags" not in d:
     try:
-      d["mkyaffs2_extra_flags"] = zip.read("META/mkyaffs2-extra-flags.txt").strip()
+      d["mkyaffs2_extra_flags"] = read_helper("META/mkyaffs2-extra-flags.txt").strip()
     except KeyError:
       # ok if flags don't exist
       pass
 
   if "recovery_api_version" not in d:
     try:
-      d["recovery_api_version"] = zip.read("META/recovery-api-version.txt").strip()
+      d["recovery_api_version"] = read_helper("META/recovery-api-version.txt").strip()
     except KeyError:
       raise ValueError("can't find recovery API version in input target-files")
 
   if "tool_extensions" not in d:
     try:
-      d["tool_extensions"] = zip.read("META/tool-extensions.txt").strip()
+      d["tool_extensions"] = read_helper("META/tool-extensions.txt").strip()
     except KeyError:
       # ok if extensions don't exist
       pass
@@ -127,7 +144,7 @@
     d["fstab_version"] = "1"
 
   try:
-    data = zip.read("META/imagesizes.txt")
+    data = read_helper("META/imagesizes.txt")
     for line in data.split("\n"):
       if not line: continue
       name, value = line.split(" ", 1)
@@ -146,39 +163,43 @@
   makeint("recovery_api_version")
   makeint("blocksize")
   makeint("system_size")
+  makeint("vendor_size")
   makeint("userdata_size")
   makeint("cache_size")
   makeint("recovery_size")
   makeint("boot_size")
   makeint("fstab_version")
 
-  d["fstab"] = LoadRecoveryFSTab(zip, d["fstab_version"])
-  d["build.prop"] = LoadBuildProp(zip)
+  d["fstab"] = LoadRecoveryFSTab(read_helper, d["fstab_version"])
+  d["build.prop"] = LoadBuildProp(read_helper)
   return d
 
-def LoadBuildProp(zip):
+def LoadBuildProp(read_helper):
   try:
-    data = zip.read("SYSTEM/build.prop")
+    data = read_helper("SYSTEM/build.prop")
   except KeyError:
     print "Warning: could not find SYSTEM/build.prop in %s" % zip
     data = ""
+  return LoadDictionaryFromLines(data.split("\n"))
 
+def LoadDictionaryFromLines(lines):
   d = {}
-  for line in data.split("\n"):
+  for line in lines:
     line = line.strip()
     if not line or line.startswith("#"): continue
-    name, value = line.split("=", 1)
-    d[name] = value
+    if "=" in line:
+      name, value = line.split("=", 1)
+      d[name] = value
   return d
 
-def LoadRecoveryFSTab(zip, fstab_version):
+def LoadRecoveryFSTab(read_helper, fstab_version):
   class Partition(object):
     pass
 
   try:
-    data = zip.read("RECOVERY/RAMDISK/etc/recovery.fstab")
+    data = read_helper("RECOVERY/RAMDISK/etc/recovery.fstab")
   except KeyError:
-    print "Warning: could not find RECOVERY/RAMDISK/etc/recovery.fstab in %s." % zip
+    print "Warning: could not find RECOVERY/RAMDISK/etc/recovery.fstab"
     data = ""
 
   if fstab_version == 1:
@@ -324,6 +345,13 @@
   assert p.returncode == 0, "mkbootimg of %s image failed" % (
       os.path.basename(sourcedir),)
 
+  if info_dict.get("verity_key", None):
+    path = "/" + os.path.basename(sourcedir).lower()
+    cmd = ["boot_signer", path, img.name, info_dict["verity_key"], img.name]
+    p = Run(cmd, stdout=subprocess.PIPE)
+    p.communicate()
+    assert p.returncode == 0, "boot_signer of %s image failed" % path
+
   img.seek(os.SEEK_SET, 0)
   data = img.read()
 
@@ -337,19 +365,28 @@
                      info_dict=None):
   """Return a File object (with name 'name') with the desired bootable
   image.  Look for it in 'unpack_dir'/BOOTABLE_IMAGES under the name
-  'prebuilt_name', otherwise construct it from the source files in
+  'prebuilt_name', otherwise look for it under 'unpack_dir'/IMAGES,
+  otherwise construct it from the source files in
   'unpack_dir'/'tree_subdir'."""
 
   prebuilt_path = os.path.join(unpack_dir, "BOOTABLE_IMAGES", prebuilt_name)
   if os.path.exists(prebuilt_path):
-    print "using prebuilt %s..." % (prebuilt_name,)
+    print "using prebuilt %s from BOOTABLE_IMAGES..." % (prebuilt_name,)
     return File.FromLocalFile(name, prebuilt_path)
-  else:
-    print "building image from target_files %s..." % (tree_subdir,)
-    fs_config = "META/" + tree_subdir.lower() + "_filesystem_config.txt"
-    return File(name, BuildBootableImage(os.path.join(unpack_dir, tree_subdir),
-                                         os.path.join(unpack_dir, fs_config),
-                                         info_dict))
+
+  prebuilt_path = os.path.join(unpack_dir, "IMAGES", prebuilt_name)
+  if os.path.exists(prebuilt_path):
+    print "using prebuilt %s from IMAGES..." % (prebuilt_name,)
+    return File.FromLocalFile(name, prebuilt_path)
+
+  print "building image from target_files %s..." % (tree_subdir,)
+  fs_config = "META/" + tree_subdir.lower() + "_filesystem_config.txt"
+  data = BuildBootableImage(os.path.join(unpack_dir, tree_subdir),
+                            os.path.join(unpack_dir, fs_config),
+                            info_dict)
+  if data:
+    return File(name, data)
+  return None
 
 
 def UnzipTemp(filename, pattern=None):
@@ -458,7 +495,7 @@
   else:
     sign_name = output_name
 
-  cmd = [OPTIONS.java_path, "-Xmx2048m", "-jar",
+  cmd = [OPTIONS.java_path, OPTIONS.java_args, "-jar",
          os.path.join(OPTIONS.search_path, OPTIONS.signapk_path)]
   cmd.extend(OPTIONS.extra_signapk_args)
   if whole_file:
@@ -490,6 +527,8 @@
   if target.endswith(".img"): target = target[:-4]
   mount_point = "/" + target
 
+  fs_type = None
+  limit = None
   if info_dict["fstab"]:
     if mount_point == "/userdata": mount_point = "/data"
     p = info_dict["fstab"][mount_point]
@@ -580,8 +619,8 @@
     opts, args = getopt.getopt(
         argv, "hvp:s:x:" + extra_opts,
         ["help", "verbose", "path=", "signapk_path=", "extra_signapk_args=",
-         "java_path=", "public_key_suffix=", "private_key_suffix=",
-         "device_specific=", "extra="] +
+         "java_path=", "java_args=", "public_key_suffix=",
+         "private_key_suffix=", "device_specific=", "extra="] +
         list(extra_long_opts))
   except getopt.GetoptError, err:
     Usage(docstring)
@@ -604,6 +643,8 @@
       OPTIONS.extra_signapk_args = shlex.split(a)
     elif o in ("--java_path",):
       OPTIONS.java_path = a
+    elif o in ("--java_args",):
+      OPTIONS.java_args = a
     elif o in ("--public_key_suffix",):
       OPTIONS.public_key_suffix = a
     elif o in ("--private_key_suffix",):
@@ -617,12 +658,22 @@
       if extra_option_handler is None or not extra_option_handler(o, a):
         assert False, "unknown option \"%s\"" % (o,)
 
-  os.environ["PATH"] = (os.path.join(OPTIONS.search_path, "bin") +
-                        os.pathsep + os.environ["PATH"])
+  if OPTIONS.search_path:
+    os.environ["PATH"] = (os.path.join(OPTIONS.search_path, "bin") +
+                          os.pathsep + os.environ["PATH"])
 
   return args
 
 
+def MakeTempFile(prefix=None, suffix=None):
+  """Make a temp file and add it to the list of things to be deleted
+  when Cleanup() is called.  Return the filename."""
+  fd, fn = tempfile.mkstemp(prefix=prefix, suffix=suffix)
+  os.close(fd)
+  OPTIONS.tempfiles.append(fn)
+  return fn
+
+
 def Cleanup():
   for i in OPTIONS.tempfiles:
     if os.path.isdir(i):
@@ -730,11 +781,14 @@
     return result
 
 
-def ZipWriteStr(zip, filename, data, perms=0644):
+def ZipWriteStr(zip, filename, data, perms=0644, compression=None):
   # use a fixed timestamp so the output is repeatable.
   zinfo = zipfile.ZipInfo(filename=filename,
                           date_time=(2009, 1, 1, 0, 0, 0))
-  zinfo.compress_type = zip.compression
+  if compression is None:
+    zinfo.compress_type = zip.compression
+  else:
+    zinfo.compress_type = compression
   zinfo.external_attr = perms << 16
   zip.writestr(zinfo, data)
 
@@ -761,6 +815,7 @@
           if x == ".py":
             f = b
           info = imp.find_module(f, [d])
+        print "loaded device-specific extensions from", path
         self.module = imp.load_module("device_specific", *info)
       except ImportError:
         print "unable to load device-specific module; assuming none"
@@ -839,8 +894,8 @@
     t.flush()
     return t
 
-  def AddToZip(self, z):
-    ZipWriteStr(z, self.name, self.data)
+  def AddToZip(self, z, compression=None):
+    ZipWriteStr(z, self.name, self.data, compression=compression)
 
 DIFF_PROGRAM_BY_EXT = {
     ".gz" : "imgdiff",
@@ -885,10 +940,26 @@
       cmd.append(ttemp.name)
       cmd.append(ptemp.name)
       p = Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-      _, err = p.communicate()
+      err = []
+      def run():
+        _, e = p.communicate()
+        if e: err.append(e)
+      th = threading.Thread(target=run)
+      th.start()
+      th.join(timeout=300)   # 5 mins
+      if th.is_alive():
+        print "WARNING: diff command timed out"
+        p.terminate()
+        th.join(5)
+        if th.is_alive():
+          p.kill()
+          th.join()
+
       if err or p.returncode != 0:
-        print "WARNING: failure running %s:\n%s\n" % (diff_program, err)
-        return None
+        print "WARNING: failure running %s:\n%s\n" % (
+            diff_program, "".join(err))
+        self.patch = None
+        return None, None, None
       diff = ptemp.read()
     finally:
       ptemp.close()
@@ -952,9 +1023,87 @@
     threads.pop().join()
 
 
+class BlockDifference:
+  def __init__(self, partition, tgt, src=None, check_first_block=False):
+    self.tgt = tgt
+    self.src = src
+    self.partition = partition
+    self.check_first_block = check_first_block
+
+    version = 1
+    if OPTIONS.info_dict:
+      version = max(
+          int(i) for i in
+          OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
+
+    b = blockimgdiff.BlockImageDiff(tgt, src, threads=OPTIONS.worker_threads,
+                                    version=version)
+    tmpdir = tempfile.mkdtemp()
+    OPTIONS.tempfiles.append(tmpdir)
+    self.path = os.path.join(tmpdir, partition)
+    b.Compute(self.path)
+
+    _, self.device = GetTypeAndDevice("/" + partition, OPTIONS.info_dict)
+
+  def WriteScript(self, script, output_zip, progress=None):
+    if not self.src:
+      # write the output unconditionally
+      if progress: script.ShowProgress(progress, 0)
+      self._WriteUpdate(script, output_zip)
+
+    else:
+      if self.check_first_block:
+        self._CheckFirstBlock(script)
+
+      script.AppendExtra('if range_sha1("%s", "%s") == "%s" then' %
+                         (self.device, self.src.care_map.to_string_raw(),
+                          self.src.TotalSha1()))
+      script.Print("Patching %s image..." % (self.partition,))
+      if progress: script.ShowProgress(progress, 0)
+      self._WriteUpdate(script, output_zip)
+      script.AppendExtra(('else\n'
+                          '  (range_sha1("%s", "%s") == "%s") ||\n'
+                          '  abort("%s partition has unexpected contents");\n'
+                          'endif;') %
+                         (self.device, self.tgt.care_map.to_string_raw(),
+                          self.tgt.TotalSha1(), self.partition))
+
+  def _WriteUpdate(self, script, output_zip):
+    partition = self.partition
+    with open(self.path + ".transfer.list", "rb") as f:
+      ZipWriteStr(output_zip, partition + ".transfer.list", f.read())
+    with open(self.path + ".new.dat", "rb") as f:
+      ZipWriteStr(output_zip, partition + ".new.dat", f.read())
+    with open(self.path + ".patch.dat", "rb") as f:
+      ZipWriteStr(output_zip, partition + ".patch.dat", f.read(),
+                         compression=zipfile.ZIP_STORED)
+
+    call = (('block_image_update("%s", '
+             'package_extract_file("%s.transfer.list"), '
+             '"%s.new.dat", "%s.patch.dat");\n') %
+            (self.device, partition, partition, partition))
+    script.AppendExtra(script._WordWrap(call))
+
+  def _CheckFirstBlock(self, script):
+    r = RangeSet((0, 1))
+    h = sha1()
+    for data in self.src.ReadRangeSet(r):
+      h.update(data)
+    h = h.hexdigest()
+
+    script.AppendExtra(('(range_sha1("%s", "%s") == "%s") || '
+                        'abort("%s has been remounted R/W; '
+                        'reflash device to reenable OTA updates");')
+                       % (self.device, r.to_string_raw(), h, self.device))
+
+
+DataImage = blockimgdiff.DataImage
+
+
 # map recovery.fstab's fs_types to mount/format "partition types"
 PARTITION_TYPES = { "yaffs2": "MTD", "mtd": "MTD",
-                    "ext4": "EMMC", "emmc": "EMMC" }
+                    "ext4": "EMMC", "emmc": "EMMC",
+                    "f2fs": "EMMC" }
 
 def GetTypeAndDevice(mount_point, info):
   fstab = info["fstab"]
@@ -977,3 +1126,76 @@
       save = True
   cert = "".join(cert).decode('base64')
   return cert
+
+def MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img,
+                      info_dict=None):
+  """Generate a binary patch that creates the recovery image starting
+  with the boot image.  (Most of the space in these images is just the
+  kernel, which is identical for the two, so the resulting patch
+  should be efficient.)  Add it to the output zip, along with a shell
+  script that is run from init.rc on first boot to actually do the
+  patching and install the new recovery image.
+
+  recovery_img and boot_img should be File objects for the
+  corresponding images.  info should be the dictionary returned by
+  common.LoadInfoDict() on the input target_files.
+  """
+
+  if info_dict is None:
+    info_dict = OPTIONS.info_dict
+
+  diff_program = ["imgdiff"]
+  path = os.path.join(input_dir, "SYSTEM", "etc", "recovery-resource.dat")
+  if os.path.exists(path):
+    diff_program.append("-b")
+    diff_program.append(path)
+    bonus_args = "-b /system/etc/recovery-resource.dat"
+  else:
+    bonus_args = ""
+
+  d = Difference(recovery_img, boot_img, diff_program=diff_program)
+  _, _, patch = d.ComputePatch()
+  output_sink("recovery-from-boot.p", patch)
+
+  td_pair = GetTypeAndDevice("/boot", info_dict)
+  if not td_pair:
+    return
+  boot_type, boot_device = td_pair
+  td_pair = GetTypeAndDevice("/recovery", info_dict)
+  if not td_pair:
+    return
+  recovery_type, recovery_device = td_pair
+
+  sh = """#!/system/bin/sh
+if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then
+  applypatch %(bonus_args)s %(boot_type)s:%(boot_device)s:%(boot_size)d:%(boot_sha1)s %(recovery_type)s:%(recovery_device)s %(recovery_sha1)s %(recovery_size)d %(boot_sha1)s:/system/recovery-from-boot.p && log -t recovery "Installing new recovery image: succeeded" || log -t recovery "Installing new recovery image: failed"
+else
+  log -t recovery "Recovery image already installed"
+fi
+""" % { 'boot_size': boot_img.size,
+        'boot_sha1': boot_img.sha1,
+        'recovery_size': recovery_img.size,
+        'recovery_sha1': recovery_img.sha1,
+        'boot_type': boot_type,
+        'boot_device': boot_device,
+        'recovery_type': recovery_type,
+        'recovery_device': recovery_device,
+        'bonus_args': bonus_args,
+        }
+
+  # The install script location moved from /system/etc to /system/bin
+  # in the L release.  Parse the init.rc file to find out where the
+  # target-files expects it to be, and put it there.
+  sh_location = "etc/install-recovery.sh"
+  try:
+    with open(os.path.join(input_dir, "BOOT", "RAMDISK", "init.rc")) as f:
+      for line in f:
+        m = re.match("^service flash_recovery /system/(\S+)\s*$", line)
+        if m:
+          sh_location = m.group(1)
+          print "putting script in", sh_location
+          break
+  except (OSError, IOError), e:
+    print "failed to read init.rc: %s" % (e,)
+
+  output_sink(sh_location, sh)
diff --git a/tools/releasetools/edify_generator.py b/tools/releasetools/edify_generator.py
index 426b713..2bd071d 100644
--- a/tools/releasetools/edify_generator.py
+++ b/tools/releasetools/edify_generator.py
@@ -68,19 +68,43 @@
     with temporary=True) to this one."""
     self.script.extend(other.script)
 
+  def AssertOemProperty(self, name, value):
+    """Assert that a property on the OEM paritition matches a value."""
+    if not name:
+      raise ValueError("must specify an OEM property")
+    if not value:
+      raise ValueError("must specify the OEM value")
+    cmd = ('file_getprop("/oem/oem.prop", "%s") == "%s" || '
+           'abort("This package expects the value \\"%s\\"  for '
+           '\\"%s\\" on the OEM partition; '
+           'this has value \\"" + file_getprop("/oem/oem.prop") + "\\".");'
+           ) % (name, value, name, value)
+    self.script.append(cmd)
+
   def AssertSomeFingerprint(self, *fp):
-    """Assert that the current system build fingerprint is one of *fp."""
+    """Assert that the current recovery build fingerprint is one of *fp."""
     if not fp:
       raise ValueError("must specify some fingerprints")
     cmd = (
-           ' ||\n    '.join([('file_getprop("/system/build.prop", '
-                         '"ro.build.fingerprint") == "%s"')
+           ' ||\n    '.join([('getprop("ro.build.fingerprint") == "%s"')
                         % i for i in fp]) +
            ' ||\n    abort("Package expects build fingerprint of %s; this '
            'device has " + getprop("ro.build.fingerprint") + ".");'
            ) % (" or ".join(fp),)
     self.script.append(cmd)
 
+  def AssertSomeThumbprint(self, *fp):
+    """Assert that the current recovery build thumbprint is one of *fp."""
+    if not fp:
+      raise ValueError("must specify some thumbprints")
+    cmd = (
+           ' ||\n    '.join([('getprop("ro.build.thumbprint") == "%s"')
+                        % i for i in fp]) +
+           ' ||\n    abort("Package expects build thumbprint of %s; this '
+           'device has " + getprop("ro.build.thumbprint") + ".");'
+           ) % (" or ".join(fp),)
+    self.script.append(cmd)
+
   def AssertOlderBuild(self, timestamp, timestamp_text):
     """Assert that the build on the device is older (or the same as)
     the given timestamp."""
@@ -178,6 +202,15 @@
                          (p.fs_type, common.PARTITION_TYPES[p.fs_type],
                           p.device, p.length, p.mount_point))
 
+  def WipeBlockDevice(self, partition):
+    if partition not in ("/system", "/vendor"):
+      raise ValueError(("WipeBlockDevice doesn't work on %s\n") % (partition,))
+    fstab = self.info.get("fstab", None)
+    size = self.info.get(partition.lstrip("/") + "_size", None)
+    device = fstab[partition].device
+
+    self.script.append('wipe_block_device("%s", %s);' % (device, size))
+
   def DeleteFiles(self, file_list):
     """Delete all files in file_list."""
     if not file_list: return
@@ -212,7 +245,7 @@
     cmd = "".join(cmd)
     self.script.append(self._WordWrap(cmd))
 
-  def WriteRawImage(self, mount_point, fn):
+  def WriteRawImage(self, mount_point, fn, mapfn=None):
     """Write the given package file into the partition for the given
     mount point."""
 
@@ -226,8 +259,13 @@
             'write_raw_image(package_extract_file("%(fn)s"), "%(device)s");'
             % args)
       elif partition_type == "EMMC":
-        self.script.append(
-            'package_extract_file("%(fn)s", "%(device)s");' % args)
+        if mapfn:
+          args["map"] = mapfn
+          self.script.append(
+              'package_extract_file("%(fn)s", "%(device)s", "%(map)s");' % args)
+        else:
+          self.script.append(
+              'package_extract_file("%(fn)s", "%(device)s");' % args)
       else:
         raise ValueError("don't know how to write \"%s\" partitions" % (p.fs_type,))
 
@@ -293,6 +331,6 @@
     if input_path is None:
       data = input_zip.read("OTA/bin/updater")
     else:
-      data = open(os.path.join(input_path, "updater")).read()
+      data = open(input_path, "rb").read()
     common.ZipWriteStr(output_zip, "META-INF/com/google/android/update-binary",
                        data, perms=0755)
diff --git a/tools/releasetools/img_from_target_files b/tools/releasetools/img_from_target_files
deleted file mode 100755
index e894c42..0000000
--- a/tools/releasetools/img_from_target_files
+++ /dev/null
@@ -1,270 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2008 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.
-
-"""
-Given a target-files zipfile, produces an image zipfile suitable for
-use with 'fastboot update'.
-
-Usage:  img_from_target_files [flags] input_target_files output_image_zip
-
-  -b  (--board_config)  <file>
-      Deprecated.
-
-  -z  (--bootable_zip)
-      Include only the bootable images (eg 'boot' and 'recovery') in
-      the output.
-
-"""
-
-import sys
-
-if sys.hexversion < 0x02040000:
-  print >> sys.stderr, "Python 2.4 or newer is required."
-  sys.exit(1)
-
-import errno
-import os
-import re
-import shutil
-import subprocess
-import tempfile
-import zipfile
-
-# missing in Python 2.4 and before
-if not hasattr(os, "SEEK_SET"):
-  os.SEEK_SET = 0
-
-import build_image
-import common
-
-OPTIONS = common.OPTIONS
-
-
-def AddSystem(output_zip):
-  """Turn the contents of SYSTEM into a system image and store it in
-  output_zip."""
-
-  print "creating system.img..."
-
-  img = tempfile.NamedTemporaryFile()
-
-  # The name of the directory it is making an image out of matters to
-  # mkyaffs2image.  It wants "system" but we have a directory named
-  # "SYSTEM", so create a symlink.
-  try:
-    os.symlink(os.path.join(OPTIONS.input_tmp, "SYSTEM"),
-               os.path.join(OPTIONS.input_tmp, "system"))
-  except OSError, e:
-      # bogus error on my mac version?
-      #   File "./build/tools/releasetools/img_from_target_files", line 86, in AddSystem
-      #     os.path.join(OPTIONS.input_tmp, "system"))
-      # OSError: [Errno 17] File exists
-    if (e.errno == errno.EEXIST):
-      pass
-
-  image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict,
-                                                    "system")
-  fstab = OPTIONS.info_dict["fstab"]
-  if fstab:
-    image_props["fs_type" ] = fstab["/system"].fs_type
-  succ = build_image.BuildImage(os.path.join(OPTIONS.input_tmp, "system"),
-                                image_props, img.name)
-  assert succ, "build system.img image failed"
-
-  img.seek(os.SEEK_SET, 0)
-  data = img.read()
-  img.close()
-
-  common.CheckSize(data, "system.img", OPTIONS.info_dict)
-  common.ZipWriteStr(output_zip, "system.img", data)
-
-
-def AddVendor(output_zip):
-  """Turn the contents of VENDOR into vendor.img and store it in
-  output_zip."""
-
-  image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict,
-                                                    "vendor")
-  # The build system has to explicitly request for vendor.img.
-  if "fs_type" not in image_props:
-    return
-
-  print "creating vendor.img..."
-
-  img = tempfile.NamedTemporaryFile()
-
-  # The name of the directory it is making an image out of matters to
-  # mkyaffs2image.  It wants "vendor" but we have a directory named
-  # "VENDOR", so create a symlink or an empty directory if VENDOR does not
-  # exist.
-  if not os.path.exists(os.path.join(OPTIONS.input_tmp, "vendor")):
-    if os.path.exists(os.path.join(OPTIONS.input_tmp, "VENDOR")):
-      os.symlink(os.path.join(OPTIONS.input_tmp, "VENDOR"),
-                 os.path.join(OPTIONS.input_tmp, "vendor"))
-    else:
-      os.mkdir(os.path.join(OPTIONS.input_tmp, "vendor"))
-
-  img = tempfile.NamedTemporaryFile()
-
-  fstab = OPTIONS.info_dict["fstab"]
-  if fstab:
-    image_props["fs_type" ] = fstab["/vendor"].fs_type
-  succ = build_image.BuildImage(os.path.join(OPTIONS.input_tmp, "vendor"),
-                                image_props, img.name)
-  assert succ, "build vendor.img image failed"
-
-  common.CheckSize(img.name, "vendor.img", OPTIONS.info_dict)
-  output_zip.write(img.name, "vendor.img")
-  img.close()
-
-
-def AddUserdata(output_zip):
-  """Create an empty userdata image and store it in output_zip."""
-
-  image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict,
-                                                    "data")
-  # If no userdata_size is provided for extfs, skip userdata.img.
-  if (image_props.get("fs_type", "").startswith("ext") and
-      not image_props.get("partition_size")):
-    return
-
-  print "creating userdata.img..."
-
-  # The name of the directory it is making an image out of matters to
-  # mkyaffs2image.  So we create a temp dir, and within it we create an
-  # empty dir named "data", and build the image from that.
-  temp_dir = tempfile.mkdtemp()
-  user_dir = os.path.join(temp_dir, "data")
-  os.mkdir(user_dir)
-  img = tempfile.NamedTemporaryFile()
-
-  fstab = OPTIONS.info_dict["fstab"]
-  if fstab:
-    image_props["fs_type" ] = fstab["/data"].fs_type
-  succ = build_image.BuildImage(user_dir, image_props, img.name)
-  assert succ, "build userdata.img image failed"
-
-  common.CheckSize(img.name, "userdata.img", OPTIONS.info_dict)
-  output_zip.write(img.name, "userdata.img")
-  img.close()
-  os.rmdir(user_dir)
-  os.rmdir(temp_dir)
-
-
-def AddCache(output_zip):
-  """Create an empty cache image and store it in output_zip."""
-
-  image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict,
-                                                    "cache")
-  # The build system has to explicitly request for cache.img.
-  if "fs_type" not in image_props:
-    return
-
-  print "creating cache.img..."
-
-  # The name of the directory it is making an image out of matters to
-  # mkyaffs2image.  So we create a temp dir, and within it we create an
-  # empty dir named "cache", and build the image from that.
-  temp_dir = tempfile.mkdtemp()
-  user_dir = os.path.join(temp_dir, "cache")
-  os.mkdir(user_dir)
-  img = tempfile.NamedTemporaryFile()
-
-  fstab = OPTIONS.info_dict["fstab"]
-  if fstab:
-    image_props["fs_type" ] = fstab["/cache"].fs_type
-  succ = build_image.BuildImage(user_dir, image_props, img.name)
-  assert succ, "build cache.img image failed"
-
-  common.CheckSize(img.name, "cache.img", OPTIONS.info_dict)
-  output_zip.write(img.name, "cache.img")
-  img.close()
-  os.rmdir(user_dir)
-  os.rmdir(temp_dir)
-
-
-def CopyInfo(output_zip):
-  """Copy the android-info.txt file from the input to the output."""
-  output_zip.write(os.path.join(OPTIONS.input_tmp, "OTA", "android-info.txt"),
-                   "android-info.txt")
-
-
-def main(argv):
-  bootable_only = [False]
-
-  def option_handler(o, a):
-    if o in ("-b", "--board_config"):
-      pass       # deprecated
-    if o in ("-z", "--bootable_zip"):
-      bootable_only[0] = True
-    else:
-      return False
-    return True
-
-  args = common.ParseOptions(argv, __doc__,
-                             extra_opts="b:z",
-                             extra_long_opts=["board_config=",
-                                              "bootable_zip"],
-                             extra_option_handler=option_handler)
-
-  bootable_only = bootable_only[0]
-
-  if len(args) != 2:
-    common.Usage(__doc__)
-    sys.exit(1)
-
-  OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
-  OPTIONS.info_dict = common.LoadInfoDict(input_zip)
-
-  # If this image was originally labelled with SELinux contexts, make sure we
-  # also apply the labels in our new image. During building, the "file_contexts"
-  # is in the out/ directory tree, but for repacking from target-files.zip it's
-  # in the root directory of the ramdisk.
-  if "selinux_fc" in OPTIONS.info_dict:
-    OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK",
-        "file_contexts")
-
-  output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
-
-  common.GetBootableImage(
-      "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT").AddToZip(output_zip)
-  common.GetBootableImage(
-      "recovery.img", "recovery.img", OPTIONS.input_tmp,
-      "RECOVERY").AddToZip(output_zip)
-
-  if not bootable_only:
-    AddSystem(output_zip)
-    AddVendor(output_zip)
-    AddUserdata(output_zip)
-    AddCache(output_zip)
-    CopyInfo(output_zip)
-
-  print "cleaning up..."
-  output_zip.close()
-  shutil.rmtree(OPTIONS.input_tmp)
-
-  print "done."
-
-
-if __name__ == '__main__':
-  try:
-    common.CloseInheritedPipes()
-    main(sys.argv[1:])
-  except common.ExternalError, e:
-    print
-    print "   ERROR: %s" % (e,)
-    print
-    sys.exit(1)
diff --git a/tools/releasetools/img_from_target_files b/tools/releasetools/img_from_target_files
new file mode 120000
index 0000000..afaf24b
--- /dev/null
+++ b/tools/releasetools/img_from_target_files
@@ -0,0 +1 @@
+img_from_target_files.py
\ No newline at end of file
diff --git a/tools/releasetools/img_from_target_files.py b/tools/releasetools/img_from_target_files.py
new file mode 100755
index 0000000..4b88e73
--- /dev/null
+++ b/tools/releasetools/img_from_target_files.py
@@ -0,0 +1,156 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2008 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.
+
+"""
+Given a target-files zipfile, produces an image zipfile suitable for
+use with 'fastboot update'.
+
+Usage:  img_from_target_files [flags] input_target_files output_image_zip
+
+  -z  (--bootable_zip)
+      Include only the bootable images (eg 'boot' and 'recovery') in
+      the output.
+
+"""
+
+import sys
+
+if sys.hexversion < 0x02070000:
+  print >> sys.stderr, "Python 2.7 or newer is required."
+  sys.exit(1)
+
+import errno
+import os
+import re
+import shutil
+import subprocess
+import tempfile
+import zipfile
+
+# missing in Python 2.4 and before
+if not hasattr(os, "SEEK_SET"):
+  os.SEEK_SET = 0
+
+import common
+
+OPTIONS = common.OPTIONS
+
+
+def CopyInfo(output_zip):
+  """Copy the android-info.txt file from the input to the output."""
+  output_zip.write(os.path.join(OPTIONS.input_tmp, "OTA", "android-info.txt"),
+                   "android-info.txt")
+
+
+def main(argv):
+  bootable_only = [False]
+
+  def option_handler(o, a):
+    if o in ("-z", "--bootable_zip"):
+      bootable_only[0] = True
+    else:
+      return False
+    return True
+
+  args = common.ParseOptions(argv, __doc__,
+                             extra_opts="z",
+                             extra_long_opts=["bootable_zip"],
+                             extra_option_handler=option_handler)
+
+  bootable_only = bootable_only[0]
+
+  if len(args) != 2:
+    common.Usage(__doc__)
+    sys.exit(1)
+
+  OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
+  output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
+  CopyInfo(output_zip)
+
+  try:
+    done = False
+    images_path = os.path.join(OPTIONS.input_tmp, "IMAGES")
+    if os.path.exists(images_path):
+      # If this is a new target-files, it already contains the images,
+      # and all we have to do is copy them to the output zip.
+      images = os.listdir(images_path)
+      if images:
+        for i in images:
+          if bootable_only and i not in ("boot.img", "recovery.img"): continue
+          if not i.endswith(".img"): continue
+          with open(os.path.join(images_path, i), "r") as f:
+            common.ZipWriteStr(output_zip, i, f.read())
+        done = True
+
+    if not done:
+      # We have an old target-files that doesn't already contain the
+      # images, so build them.
+      import add_img_to_target_files
+
+      OPTIONS.info_dict = common.LoadInfoDict(input_zip)
+
+      # If this image was originally labelled with SELinux contexts,
+      # make sure we also apply the labels in our new image. During
+      # building, the "file_contexts" is in the out/ directory tree,
+      # but for repacking from target-files.zip it's in the root
+      # directory of the ramdisk.
+      if "selinux_fc" in OPTIONS.info_dict:
+        OPTIONS.info_dict["selinux_fc"] = os.path.join(
+            OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")
+
+      boot_image = common.GetBootableImage(
+          "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
+      if boot_image:
+          boot_image.AddToZip(output_zip)
+      recovery_image = common.GetBootableImage(
+          "recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
+      if recovery_image:
+        recovery_image.AddToZip(output_zip)
+
+      def banner(s):
+        print "\n\n++++ " + s + " ++++\n\n"
+
+      if not bootable_only:
+        banner("AddSystem")
+        add_img_to_target_files.AddSystem(output_zip, prefix="")
+        try:
+          input_zip.getinfo("VENDOR/")
+          banner("AddVendor")
+          add_img_to_target_files.AddVendor(output_zip, prefix="")
+        except KeyError:
+          pass   # no vendor partition for this device
+        banner("AddUserdata")
+        add_img_to_target_files.AddUserdata(output_zip, prefix="")
+        banner("AddCache")
+        add_img_to_target_files.AddCache(output_zip, prefix="")
+
+  finally:
+    print "cleaning up..."
+    output_zip.close()
+    shutil.rmtree(OPTIONS.input_tmp)
+
+  print "done."
+
+
+if __name__ == '__main__':
+  try:
+    common.CloseInheritedPipes()
+    main(sys.argv[1:])
+  except common.ExternalError, e:
+    print
+    print "   ERROR: %s" % (e,)
+    print
+    sys.exit(1)
diff --git a/tools/releasetools/make_recovery_patch b/tools/releasetools/make_recovery_patch
new file mode 100755
index 0000000..08d1450
--- /dev/null
+++ b/tools/releasetools/make_recovery_patch
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+#
+# 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.
+
+import sys
+
+if sys.hexversion < 0x02070000:
+  print >> sys.stderr, "Python 2.7 or newer is required."
+  sys.exit(1)
+
+import os
+import common
+
+OPTIONS = common.OPTIONS
+
+def main(argv):
+  # def option_handler(o, a):
+  #   return False
+
+  args = common.ParseOptions(argv, __doc__)
+  input_dir, output_dir = args
+
+  OPTIONS.info_dict = common.LoadInfoDict(input_dir)
+
+  recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
+                                         input_dir, "RECOVERY")
+  boot_img = common.GetBootableImage("boot.img", "boot.img",
+                                     input_dir, "BOOT")
+
+  if not recovery_img or not boot_img:
+    sys.exit(0)
+
+  def output_sink(fn, data):
+    with open(os.path.join(output_dir, "SYSTEM", *fn.split("/")), "wb") as f:
+      f.write(data)
+
+  common.MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img)
+
+
+if __name__ == '__main__':
+  main(sys.argv[1:])
diff --git a/tools/releasetools/ota_from_target_files b/tools/releasetools/ota_from_target_files
index e695218..e8dff5a 100755
--- a/tools/releasetools/ota_from_target_files
+++ b/tools/releasetools/ota_from_target_files
@@ -21,7 +21,7 @@
 
 Usage:  ota_from_target_files [flags] input_target_files output_ota_package
 
-  -b  (--board_config)  <file>
+  --board_config  <file>
       Deprecated.
 
   -k (--package_key) <key> Key to use to sign the package (default is
@@ -37,6 +37,10 @@
       Generate an incremental OTA using the given target-files zip as
       the starting build.
 
+  -o  (--oem_settings)  <file>
+      Use the file to specify the expected OEM-specific properties
+      on the OEM partition of the intended device.
+
   -w  (--wipe_user_data)
       Generate an OTA package that will wipe the user data partition
       when installed.
@@ -57,6 +61,16 @@
       first, so that any changes made to the system partition are done
       using the new recovery (new kernel, etc.).
 
+  --block
+      Generate a block-based OTA if possible.  Will fall back to a
+      file-based OTA if the target_files is older and doesn't support
+      block-based OTAs.
+
+  -b  (--binary)  <file>
+      Use the given binary as the update-binary in the output package,
+      instead of the binary in the build's target_files.  Use for
+      development only.
+
   -t  (--worker_threads) <int>
       Specifies the number of worker-threads that will be used when
       generating patches for incremental updates (defaults to 3).
@@ -65,12 +79,13 @@
 
 import sys
 
-if sys.hexversion < 0x02040000:
-  print >> sys.stderr, "Python 2.4 or newer is required."
+if sys.hexversion < 0x02070000:
+  print >> sys.stderr, "Python 2.7 or newer is required."
   sys.exit(1)
 
 import copy
 import errno
+import multiprocessing
 import os
 import re
 import subprocess
@@ -78,13 +93,13 @@
 import time
 import zipfile
 
-try:
-  from hashlib import sha1 as sha1
-except ImportError:
-  from sha import sha as sha1
+from hashlib import sha1 as sha1
 
 import common
 import edify_generator
+import build_image
+import blockimgdiff
+import sparse_img
 
 OPTIONS = common.OPTIONS
 OPTIONS.package_key = None
@@ -96,9 +111,15 @@
 OPTIONS.omit_prereq = False
 OPTIONS.extra_script = None
 OPTIONS.aslr_mode = True
-OPTIONS.worker_threads = 3
+OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
+if OPTIONS.worker_threads == 0:
+  OPTIONS.worker_threads = 1
 OPTIONS.two_step = False
 OPTIONS.no_signing = False
+OPTIONS.block_based = False
+OPTIONS.updater_binary = None
+OPTIONS.oem_source = None
+OPTIONS.fallback_to_full = True
 
 def MostPopularKey(d, default):
   """Given a dict, return the key corresponding to the largest
@@ -144,50 +165,21 @@
     return result
   return None
 
-class Item:
-  """Items represent the metadata (user, group, mode) of files and
-  directories in the system image."""
-  ITEMS = {}
-  def __init__(self, name, dir=False):
-    self.name = name
-    self.uid = None
-    self.gid = None
-    self.mode = None
-    self.selabel = None
-    self.capabilities = None
-    self.dir = dir
+class ItemSet:
+  def __init__(self, partition, fs_config):
+    self.partition = partition
+    self.fs_config = fs_config
+    self.ITEMS = {}
 
-    if name:
-      self.parent = Item.Get(os.path.dirname(name), dir=True)
-      self.parent.children.append(self)
-    else:
-      self.parent = None
-    if dir:
-      self.children = []
+  def Get(self, name, dir=False):
+    if name not in self.ITEMS:
+      self.ITEMS[name] = Item(self, name, dir=dir)
+    return self.ITEMS[name]
 
-  def Dump(self, indent=0):
-    if self.uid is not None:
-      print "%s%s %d %d %o" % ("  "*indent, self.name, self.uid, self.gid, self.mode)
-    else:
-      print "%s%s %s %s %s" % ("  "*indent, self.name, self.uid, self.gid, self.mode)
-    if self.dir:
-      print "%s%s" % ("  "*indent, self.descendants)
-      print "%s%s" % ("  "*indent, self.best_subtree)
-      for i in self.children:
-        i.Dump(indent=indent+1)
-
-  @classmethod
-  def Get(cls, name, dir=False):
-    if name not in cls.ITEMS:
-      cls.ITEMS[name] = Item(name, dir=dir)
-    return cls.ITEMS[name]
-
-  @classmethod
-  def GetMetadata(cls, input_zip):
-
+  def GetMetadata(self, input_zip):
     # The target_files contains a record of what the uid,
     # gid, and mode are supposed to be.
-    output = input_zip.read("META/filesystem_config.txt")
+    output = input_zip.read(self.fs_config)
 
     for line in output.split("\n"):
       if not line: continue
@@ -205,7 +197,7 @@
         if key == "capabilities":
           capabilities = value
 
-      i = cls.ITEMS.get(name, None)
+      i = self.ITEMS.get(name, None)
       if i is not None:
         i.uid = int(uid)
         i.gid = int(gid)
@@ -216,11 +208,44 @@
           i.children.sort(key=lambda i: i.name)
 
     # set metadata for the files generated by this script.
-    i = cls.ITEMS.get("system/recovery-from-boot.p", None)
+    i = self.ITEMS.get("system/recovery-from-boot.p", None)
     if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0644, None, None
-    i = cls.ITEMS.get("system/etc/install-recovery.sh", None)
+    i = self.ITEMS.get("system/etc/install-recovery.sh", None)
     if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0544, None, None
 
+
+class Item:
+  """Items represent the metadata (user, group, mode) of files and
+  directories in the system image."""
+  def __init__(self, itemset, name, dir=False):
+    self.itemset = itemset
+    self.name = name
+    self.uid = None
+    self.gid = None
+    self.mode = None
+    self.selabel = None
+    self.capabilities = None
+    self.dir = dir
+
+    if name:
+      self.parent = itemset.Get(os.path.dirname(name), dir=True)
+      self.parent.children.append(self)
+    else:
+      self.parent = None
+    if dir:
+      self.children = []
+
+  def Dump(self, indent=0):
+    if self.uid is not None:
+      print "%s%s %d %d %o" % ("  "*indent, self.name, self.uid, self.gid, self.mode)
+    else:
+      print "%s%s %s %s %s" % ("  "*indent, self.name, self.uid, self.gid, self.mode)
+    if self.dir:
+      print "%s%s" % ("  "*indent, self.descendants)
+      print "%s%s" % ("  "*indent, self.best_subtree)
+      for i in self.children:
+        i.Dump(indent=indent+1)
+
   def CountChildMetadata(self):
     """Count up the (uid, gid, mode, selabel, capabilities) tuples for
     all children and determine the best strategy for using set_perm_recursive and
@@ -305,9 +330,8 @@
     recurse(self, (-1, -1, -1, -1, None, None))
 
 
-def CopySystemFiles(input_zip, output_zip=None,
-                    substitute=None):
-  """Copies files underneath system/ in the input zip to the output
+def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
+  """Copies files for the partition in the input zip to the output
   zip.  Populates the Item class with their metadata, and returns a
   list of symlinks.  output_zip may be None, in which case the copy is
   skipped (but the other side effects still happen).  substitute is an
@@ -317,15 +341,17 @@
 
   symlinks = []
 
+  partition = itemset.partition
+
   for info in input_zip.infolist():
-    if info.filename.startswith("SYSTEM/"):
+    if info.filename.startswith(partition.upper() + "/"):
       basefilename = info.filename[7:]
       if IsSymlink(info):
         symlinks.append((input_zip.read(info.filename),
-                         "/system/" + basefilename))
+                         "/" + partition + "/" + basefilename))
       else:
         info2 = copy.copy(info)
-        fn = info2.filename = "system/" + basefilename
+        fn = info2.filename = partition + "/" + basefilename
         if substitute and fn in substitute and substitute[fn] is None:
           continue
         if output_zip is not None:
@@ -335,9 +361,9 @@
             data = input_zip.read(info.filename)
           output_zip.writestr(info2, data)
         if fn.endswith("/"):
-          Item.Get(fn[:-1], dir=True)
+          itemset.Get(fn[:-1], dir=True)
         else:
-          Item.Get(fn, dir=False)
+          itemset.Get(fn, dir=False)
 
   symlinks.sort()
   return symlinks
@@ -351,63 +377,82 @@
                   whole_file=True)
 
 
-def AppendAssertions(script, info_dict):
-  device = GetBuildProp("ro.product.device", info_dict)
-  script.AssertDevice(device)
-
-
-def MakeRecoveryPatch(input_tmp, output_zip, recovery_img, boot_img):
-  """Generate a binary patch that creates the recovery image starting
-  with the boot image.  (Most of the space in these images is just the
-  kernel, which is identical for the two, so the resulting patch
-  should be efficient.)  Add it to the output zip, along with a shell
-  script that is run from init.rc on first boot to actually do the
-  patching and install the new recovery image.
-
-  recovery_img and boot_img should be File objects for the
-  corresponding images.  info should be the dictionary returned by
-  common.LoadInfoDict() on the input target_files.
-
-  Returns an Item for the shell script, which must be made
-  executable.
-  """
-
-  diff_program = ["imgdiff"]
-  path = os.path.join(input_tmp, "SYSTEM", "etc", "recovery-resource.dat")
-  if os.path.exists(path):
-    diff_program.append("-b")
-    diff_program.append(path)
-    bonus_args = "-b /system/etc/recovery-resource.dat"
+def AppendAssertions(script, info_dict, oem_dict = None):
+  oem_props = info_dict.get("oem_fingerprint_properties")
+  if oem_props is None or len(oem_props) == 0:
+    device = GetBuildProp("ro.product.device", info_dict)
+    script.AssertDevice(device)
   else:
-    bonus_args = ""
+    if oem_dict is None:
+      raise common.ExternalError("No OEM file provided to answer expected assertions")
+    for prop in oem_props.split():
+      if oem_dict.get(prop) is None:
+        raise common.ExternalError("The OEM file is missing the property %s" % prop)
+      script.AssertOemProperty(prop, oem_dict.get(prop))
 
-  d = common.Difference(recovery_img, boot_img, diff_program=diff_program)
-  _, _, patch = d.ComputePatch()
-  common.ZipWriteStr(output_zip, "recovery/recovery-from-boot.p", patch)
-  Item.Get("system/recovery-from-boot.p", dir=False)
 
-  boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
-  recovery_type, recovery_device = common.GetTypeAndDevice("/recovery", OPTIONS.info_dict)
+def HasRecoveryPatch(target_files_zip):
+  try:
+    target_files_zip.getinfo("SYSTEM/recovery-from-boot.p")
+    return True
+  except KeyError:
+    return False
 
-  sh = """#!/system/bin/sh
-if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then
-  log -t recovery "Installing new recovery image"
-  applypatch %(bonus_args)s %(boot_type)s:%(boot_device)s:%(boot_size)d:%(boot_sha1)s %(recovery_type)s:%(recovery_device)s %(recovery_sha1)s %(recovery_size)d %(boot_sha1)s:/system/recovery-from-boot.p
-else
-  log -t recovery "Recovery image already installed"
-fi
-""" % { 'boot_size': boot_img.size,
-        'boot_sha1': boot_img.sha1,
-        'recovery_size': recovery_img.size,
-        'recovery_sha1': recovery_img.sha1,
-        'boot_type': boot_type,
-        'boot_device': boot_device,
-        'recovery_type': recovery_type,
-        'recovery_device': recovery_device,
-        'bonus_args': bonus_args,
-        }
-  common.ZipWriteStr(output_zip, "recovery/etc/install-recovery.sh", sh)
-  return Item.Get("system/etc/install-recovery.sh", dir=False)
+def HasVendorPartition(target_files_zip):
+  try:
+    target_files_zip.getinfo("VENDOR/")
+    return True
+  except KeyError:
+    return False
+
+def GetOemProperty(name, oem_props, oem_dict, info_dict):
+  if oem_props is not None and name in oem_props:
+    return oem_dict[name]
+  return GetBuildProp(name, info_dict)
+
+
+def CalculateFingerprint(oem_props, oem_dict, info_dict):
+  if oem_props is None:
+    return GetBuildProp("ro.build.fingerprint", info_dict)
+  return "%s/%s/%s:%s" % (
+    GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
+    GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
+    GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
+    GetBuildProp("ro.build.thumbprint", info_dict))
+
+
+def GetImage(which, tmpdir, info_dict):
+  # Return an image object (suitable for passing to BlockImageDiff)
+  # for the 'which' partition (most be "system" or "vendor").  If a
+  # prebuilt image and file map are found in tmpdir they are used,
+  # otherwise they are reconstructed from the individual files.
+
+  assert which in ("system", "vendor")
+
+  path = os.path.join(tmpdir, "IMAGES", which + ".img")
+  mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
+  if os.path.exists(path) and os.path.exists(mappath):
+    print "using %s.img from target-files" % (which,)
+    # This is a 'new' target-files, which already has the image in it.
+
+  else:
+    print "building %s.img from target-files" % (which,)
+
+    # This is an 'old' target-files, which does not contain images
+    # already built.  Build them.
+
+    mappath = tempfile.mkstemp()[1]
+    OPTIONS.tempfiles.append(mappath)
+
+    import add_img_to_target_files
+    if which == "system":
+      path = add_img_to_target_files.BuildSystem(
+          tmpdir, info_dict, block_list=mappath)
+    elif which == "vendor":
+      path = add_img_to_target_files.BuildVendor(
+          tmpdir, info_dict, block_list=mappath)
+
+  return sparse_img.SparseImage(path, mappath)
 
 
 def WriteFullOTAPackage(input_zip, output_zip):
@@ -416,9 +461,17 @@
   # change very often.
   script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
 
-  metadata = {"post-build": GetBuildProp("ro.build.fingerprint",
-                                         OPTIONS.info_dict),
-              "pre-device": GetBuildProp("ro.product.device",
+  oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
+  oem_dict = None
+  if oem_props is not None and len(oem_props) > 0:
+    if OPTIONS.oem_source is None:
+      raise common.ExternalError("OEM source required for this build")
+    script.Mount("/oem")
+    oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
+
+  metadata = {"post-build": CalculateFingerprint(
+                               oem_props, oem_dict, OPTIONS.info_dict),
+              "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
                                          OPTIONS.info_dict),
               "post-timestamp": GetBuildProp("ro.build.date.utc",
                                              OPTIONS.info_dict),
@@ -433,12 +486,15 @@
       metadata=metadata,
       info_dict=OPTIONS.info_dict)
 
+  has_recovery_patch = HasRecoveryPatch(input_zip)
+  block_based = OPTIONS.block_based and has_recovery_patch
+
   if not OPTIONS.omit_prereq:
     ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
     ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
     script.AssertOlderBuild(ts, ts_text)
 
-  AppendAssertions(script, OPTIONS.info_dict)
+  AppendAssertions(script, OPTIONS.info_dict, oem_dict)
   device_specific.FullOTA_Assertions()
 
   # Two-step package strategy (in chronological order, which is *not*
@@ -482,37 +538,78 @@
 
   device_specific.FullOTA_InstallBegin()
 
-  script.ShowProgress(0.5, 0)
+  system_progress = 0.75
 
   if OPTIONS.wipe_user_data:
-    script.FormatPartition("/data")
+    system_progress -= 0.1
+  if HasVendorPartition(input_zip):
+    system_progress -= 0.1
 
   if "selinux_fc" in OPTIONS.info_dict:
     WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
 
-  script.FormatPartition("/system")
-  script.Mount("/system")
-  script.UnpackPackageDir("recovery", "/system")
-  script.UnpackPackageDir("system", "/system")
+  system_items = ItemSet("system", "META/filesystem_config.txt")
+  script.ShowProgress(system_progress, 0)
+  if block_based:
+    # Full OTA is done as an "incremental" against an empty source
+    # image.  This has the effect of writing new data from the package
+    # to the entire partition, but lets us reuse the updater code that
+    # writes incrementals to do it.
+    system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
+    system_tgt.ResetFileMap()
+    system_diff = common.BlockDifference("system", system_tgt, src=None)
+    system_diff.WriteScript(script, output_zip)
+  else:
+    script.FormatPartition("/system")
+    script.Mount("/system")
+    if not has_recovery_patch:
+      script.UnpackPackageDir("recovery", "/system")
+    script.UnpackPackageDir("system", "/system")
 
-  symlinks = CopySystemFiles(input_zip, output_zip)
-  script.MakeSymlinks(symlinks)
+    symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
+    script.MakeSymlinks(symlinks)
 
   boot_img = common.GetBootableImage("boot.img", "boot.img",
                                      OPTIONS.input_tmp, "BOOT")
-  MakeRecoveryPatch(OPTIONS.input_tmp, output_zip, recovery_img, boot_img)
 
-  Item.GetMetadata(input_zip)
-  Item.Get("system").SetPermissions(script)
+  if not block_based:
+    def output_sink(fn, data):
+      common.ZipWriteStr(output_zip, "recovery/" + fn, data)
+      system_items.Get("system/" + fn, dir=False)
+
+    common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
+                             recovery_img, boot_img)
+
+    system_items.GetMetadata(input_zip)
+    system_items.Get("system").SetPermissions(script)
+
+  if HasVendorPartition(input_zip):
+    vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
+    script.ShowProgress(0.1, 0)
+
+    if block_based:
+      vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
+      vendor_tgt.ResetFileMap()
+      vendor_diff = common.BlockDifference("vendor", vendor_tgt)
+      vendor_diff.WriteScript(script, output_zip)
+    else:
+      script.FormatPartition("/vendor")
+      script.Mount("/vendor")
+      script.UnpackPackageDir("vendor", "/vendor")
+
+      symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
+      script.MakeSymlinks(symlinks)
+
+      vendor_items.GetMetadata(input_zip)
+      vendor_items.Get("vendor").SetPermissions(script)
 
   common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
   common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
-  script.ShowProgress(0.2, 0)
 
-  script.ShowProgress(0.2, 10)
+  script.ShowProgress(0.05, 5)
   script.WriteRawImage("/boot", "boot.img")
 
-  script.ShowProgress(0.1, 0)
+  script.ShowProgress(0.2, 10)
   device_specific.FullOTA_InstallEnd()
 
   if OPTIONS.extra_script is not None:
@@ -520,6 +617,10 @@
 
   script.UnmountAll()
 
+  if OPTIONS.wipe_user_data:
+    script.ShowProgress(0.1, 10)
+    script.FormatPartition("/data")
+
   if OPTIONS.two_step:
     script.AppendExtra("""
 set_stage("%(bcb_dev)s", "");
@@ -532,9 +633,10 @@
 endif;
 endif;
 """ % bcb_dev)
-  script.AddToZip(input_zip, output_zip)
+  script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
   WriteMetadata(metadata, output_zip)
 
+
 def WritePolicyConfig(file_context, output_zip):
   f = open(file_context, 'r');
   basename = os.path.basename(file_context)
@@ -546,14 +648,16 @@
                      "".join(["%s=%s\n" % kv
                               for kv in sorted(metadata.iteritems())]))
 
-def LoadSystemFiles(z):
-  """Load all the files from SYSTEM/... in a given target-files
+
+def LoadPartitionFiles(z, partition):
+  """Load all the files from the given partition in a given target-files
   ZipFile, and return a dict of {filename: File object}."""
   out = {}
+  prefix = partition.upper() + "/"
   for info in z.infolist():
-    if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
+    if info.filename.startswith(prefix) and not IsSymlink(info):
       basefilename = info.filename[7:]
-      fn = "system/" + basefilename
+      fn = partition + "/" + basefilename
       data = z.read(info.filename)
       out[fn] = common.File(fn, data)
   return out
@@ -564,7 +668,8 @@
   try:
     return info_dict.get("build.prop", {})[prop]
   except KeyError:
-    raise common.ExternalError("couldn't find %s in build.prop" % (property,))
+    raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
+
 
 def AddToKnownPaths(filename, known_paths):
   if filename[-1] == "/":
@@ -577,7 +682,8 @@
     known_paths.add(path)
     dirs.pop()
 
-def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
+
+def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
   source_version = OPTIONS.source_info_dict["recovery_api_version"]
   target_version = OPTIONS.target_info_dict["recovery_api_version"]
 
@@ -603,81 +709,375 @@
       metadata=metadata,
       info_dict=OPTIONS.info_dict)
 
-  print "Loading target..."
-  target_data = LoadSystemFiles(target_zip)
-  print "Loading source..."
-  source_data = LoadSystemFiles(source_zip)
-
-  verbatim_targets = []
-  patch_list = []
-  diffs = []
-  renames = {}
-  known_paths = set()
-  largest_source_size = 0
-
-  matching_file_cache = {}
-  for fn, sf in source_data.items():
-    assert fn == sf.name
-    matching_file_cache["path:" + fn] = sf
-    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
-      matching_file_cache["sha:" + sf.sha1] = sf
-
-  for fn in sorted(target_data.keys()):
-    tf = target_data[fn]
-    assert fn == tf.name
-    sf = ClosestFileMatch(tf, matching_file_cache, renames)
-    if sf is not None and sf.name != tf.name:
-      print "File has moved from " + sf.name + " to " + tf.name
-      renames[sf.name] = tf
-
-    if sf is None or fn in OPTIONS.require_verbatim:
-      # This file should be included verbatim
-      if fn in OPTIONS.prohibit_verbatim:
-        raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
-      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))
-    else:
-      # Target file data identical to source (may still be renamed)
-      pass
-
-  common.ComputeDifferences(diffs)
-
-  for diff in diffs:
-    tf, sf, d = diff.GetPatch()
-    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((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)
   target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
   metadata["pre-build"] = source_fp
   metadata["post-build"] = target_fp
 
+  source_boot = common.GetBootableImage(
+      "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
+      OPTIONS.source_info_dict)
+  target_boot = common.GetBootableImage(
+      "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
+  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",
+      OPTIONS.source_info_dict)
+  target_recovery = common.GetBootableImage(
+      "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
+  updating_recovery = (source_recovery.data != target_recovery.data)
+
+  system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
+  system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
+  system_diff = common.BlockDifference("system", system_tgt, system_src,
+                                       check_first_block=True)
+
+  if HasVendorPartition(target_zip):
+    if not HasVendorPartition(source_zip):
+      raise RuntimeError("can't generate incremental that adds /vendor")
+    vendor_src = GetImage("vendor", OPTIONS.source_tmp, OPTIONS.source_info_dict)
+    vendor_tgt = GetImage("vendor", OPTIONS.target_tmp, OPTIONS.target_info_dict)
+    vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
+                                         check_first_block=True)
+  else:
+    vendor_diff = None
+
+  oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
+  oem_dict = None
+  if oem_props is not None and len(oem_props) > 0:
+    if OPTIONS.oem_source is None:
+      raise common.ExternalError("OEM source required for this build")
+    script.Mount("/oem")
+    oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
+
+  AppendAssertions(script, OPTIONS.target_info_dict, oem_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()
+
+  if oem_props is None:
+    script.AssertSomeFingerprint(source_fp, target_fp)
+  else:
+    script.AssertSomeThumbprint(
+        GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
+        GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
+
+  if updating_boot:
+    boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
+    d = common.Difference(target_boot, source_boot)
+    _, _, d = d.ComputePatch()
+    if d is None:
+      include_full_boot = True
+      common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
+    else:
+      include_full_boot = False
+
+      print "boot      target: %d  source: %d  diff: %d" % (
+          target_boot.size, source_boot.size, len(d))
+
+      common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
+
+      script.PatchCheck("%s:%s:%d:%s:%d:%s" %
+                        (boot_type, boot_device,
+                         source_boot.size, source_boot.sha1,
+                         target_boot.size, target_boot.sha1))
+
+  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()
+
+  system_diff.WriteScript(script, output_zip,
+                          progress=0.8 if vendor_diff else 0.9)
+  if vendor_diff:
+    vendor_diff.WriteScript(script, output_zip, progress=0.1)
+
+  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 not OPTIONS.two_step:
+    if updating_boot:
+      if include_full_boot:
+        print "boot image changed; including full."
+        script.Print("Installing boot image...")
+        script.WriteRawImage("/boot", "boot.img")
+      else:
+        # Produce the boot image by applying a patch to the current
+        # contents of the boot partition, and write it back to the
+        # partition.
+        print "boot image changed; including patch."
+        script.Print("Patching boot image...")
+        script.ShowProgress(0.1, 10)
+        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")
+    else:
+      print "boot image unchanged; skipping."
+
+  # Do device-specific installation (eg, write radio image).
+  device_specific.IncrementalOTA_InstallEnd()
+
+  if OPTIONS.extra_script is not None:
+    script.AppendExtra(OPTIONS.extra_script)
+
+  if OPTIONS.wipe_user_data:
+    script.Print("Erasing user data...")
+    script.FormatPartition("/data")
+
+  if OPTIONS.two_step:
+    script.AppendExtra("""
+set_stage("%(bcb_dev)s", "");
+endif;
+endif;
+""" % bcb_dev)
+
+  script.SetProgress(1)
+  script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
+  WriteMetadata(metadata, output_zip)
+
+
+class FileDifference:
+  def __init__(self, partition, source_zip, target_zip, output_zip):
+    print "Loading target..."
+    self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
+    print "Loading source..."
+    self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
+
+    self.verbatim_targets = verbatim_targets = []
+    self.patch_list = patch_list = []
+    diffs = []
+    self.renames = renames = {}
+    known_paths = set()
+    largest_source_size = 0
+
+    matching_file_cache = {}
+    for fn, sf in source_data.items():
+      assert fn == sf.name
+      matching_file_cache["path:" + fn] = sf
+      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
+        matching_file_cache["sha:" + sf.sha1] = sf
+
+    for fn in sorted(target_data.keys()):
+      tf = target_data[fn]
+      assert fn == tf.name
+      sf = ClosestFileMatch(tf, matching_file_cache, renames)
+      if sf is not None and sf.name != tf.name:
+        print "File has moved from " + sf.name + " to " + tf.name
+        renames[sf.name] = tf
+
+      if sf is None or fn in OPTIONS.require_verbatim:
+        # This file should be included verbatim
+        if fn in OPTIONS.prohibit_verbatim:
+          raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
+        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))
+      else:
+        # Target file data identical to source (may still be renamed)
+        pass
+
+    common.ComputeDifferences(diffs)
+
+    for diff in diffs:
+      tf, sf, d = diff.GetPatch()
+      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((tf, sf, tf.size, common.sha1(d).hexdigest()))
+        largest_source_size = max(largest_source_size, sf.size)
+
+    self.largest_source_size = largest_source_size
+
+  def EmitVerification(self, script):
+    so_far = 0
+    for tf, sf, size, patch_sha in self.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
+    return so_far
+
+  def RemoveUnneededFiles(self, script, extras=()):
+    script.DeleteFiles(["/"+i[0] for i in self.verbatim_targets] +
+                       ["/"+i for i in sorted(self.source_data)
+                              if i not in self.target_data and
+                              i not in self.renames] +
+                       list(extras))
+
+  def TotalPatchSize(self):
+    return sum(i[1].size for i in self.patch_list)
+
+  def EmitPatches(self, script, total_patch_size, so_far):
+    self.deferred_patch_list = deferred_patch_list = []
+    for item in self.patch_list:
+      tf, sf, size, _ = item
+      if tf.name == "system/build.prop":
+        deferred_patch_list.append(item)
+        continue
+      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)
+    return so_far
+
+  def EmitDeferredPatches(self, script):
+    for item in self.deferred_patch_list:
+      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)
+
+  def EmitRenames(self, script):
+    if len(self.renames) > 0:
+      script.Print("Renaming files...")
+      for src, tgt in self.renames.iteritems():
+        print "Renaming " + src + " to " + tgt.name
+        script.RenameFile(src, tgt.name)
+
+
+
+
+def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
+  target_has_recovery_patch = HasRecoveryPatch(target_zip)
+  source_has_recovery_patch = HasRecoveryPatch(source_zip)
+
+  if (OPTIONS.block_based and
+      target_has_recovery_patch and
+      source_has_recovery_patch):
+    return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
+
+  source_version = OPTIONS.source_info_dict["recovery_api_version"]
+  target_version = OPTIONS.target_info_dict["recovery_api_version"]
+
+  if source_version == 0:
+    print ("WARNING: generating edify script for a source that "
+           "can't install it.")
+  script = edify_generator.EdifyGenerator(source_version,
+                                          OPTIONS.target_info_dict)
+
+  oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
+  oem_dict = None
+  if oem_props is not None and len(oem_props) > 0:
+    if OPTIONS.oem_source is None:
+      raise common.ExternalError("OEM source required for this build")
+    script.Mount("/oem")
+    oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
+
+  metadata = {"pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
+                                         OPTIONS.source_info_dict),
+              "post-timestamp": GetBuildProp("ro.build.date.utc",
+                                             OPTIONS.target_info_dict),
+              }
+
+  device_specific = common.DeviceSpecificParams(
+      source_zip=source_zip,
+      source_version=source_version,
+      target_zip=target_zip,
+      target_version=target_version,
+      output_zip=output_zip,
+      script=script,
+      metadata=metadata,
+      info_dict=OPTIONS.info_dict)
+
+  system_diff = FileDifference("system", source_zip, target_zip, output_zip)
   script.Mount("/system")
-  script.AssertSomeFingerprint(source_fp, target_fp)
+  if HasVendorPartition(target_zip):
+    vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
+    script.Mount("/vendor")
+  else:
+    vendor_diff = None
+
+  target_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.target_info_dict)
+  source_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.source_info_dict)
+
+  if oem_props is None:
+    script.AssertSomeFingerprint(source_fp, target_fp)
+  else:
+    script.AssertSomeThumbprint(
+        GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
+        GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
+
+  metadata["pre-build"] = source_fp
+  metadata["post-build"] = target_fp
 
   source_boot = common.GetBootableImage(
       "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
@@ -700,7 +1100,7 @@
   #  0.1 for unpacking verbatim files, symlinking, and doing the
   #      device-specific commands.
 
-  AppendAssertions(script, OPTIONS.target_info_dict)
+  AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
   device_specific.IncrementalOTA_Assertions()
 
   # Two-step incremental package strategy (in chronological order,
@@ -748,17 +1148,9 @@
   device_specific.IncrementalOTA_VerifyBegin()
 
   script.ShowProgress(0.1, 0)
-  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 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)
+  so_far = system_diff.EmitVerification(script)
+  if vendor_diff:
+    so_far += vendor_diff.EmitVerification(script)
 
   if updating_boot:
     d = common.Difference(target_boot, source_boot)
@@ -775,10 +1167,13 @@
                        source_boot.size, source_boot.sha1,
                        target_boot.size, target_boot.sha1))
     so_far += source_boot.size
-    script.SetProgress(so_far / total_verify_size)
 
-  if patch_list or updating_recovery or updating_boot:
-    script.CacheFreeSpaceCheck(largest_source_size)
+  size = []
+  if system_diff.patch_list: size.append(system_diff.largest_source_size)
+  if vendor_diff:
+    if vendor_diff.patch_list: size.append(vendor_diff.largest_source_size)
+  if size or updating_recovery or updating_boot:
+    script.CacheFreeSpaceCheck(max(size))
 
   device_specific.IncrementalOTA_VerifyEnd()
 
@@ -799,35 +1194,23 @@
     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")
-
   script.Print("Removing unneeded files...")
-  script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
-                     ["/"+i for i in sorted(source_data)
-                            if i not in target_data and
-                            i not in renames] +
-                     ["/system/recovery.img"])
+  system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
+  if vendor_diff:
+    vendor_diff.RemoveUnneededFiles(script)
 
   script.ShowProgress(0.8, 0)
-  total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
+  total_patch_size = 1.0 + system_diff.TotalPatchSize()
+  if vendor_diff:
+    total_patch_size += vendor_diff.TotalPatchSize()
   if updating_boot:
     total_patch_size += target_boot.size
-  so_far = 0
 
   script.Print("Patching system files...")
-  deferred_patch_list = []
-  for item in patch_list:
-    tf, sf, size, _ = item
-    if tf.name == "system/build.prop":
-      deferred_patch_list.append(item)
-      continue
-    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)
+  so_far = system_diff.EmitPatches(script, total_patch_size, 0)
+  if vendor_diff:
+    script.Print("Patching vendor files...")
+    so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
 
   if not OPTIONS.two_step:
     if updating_boot:
@@ -848,6 +1231,10 @@
     else:
       print "boot image unchanged; skipping."
 
+  system_items = ItemSet("system", "META/filesystem_config.txt")
+  if vendor_diff:
+    vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
+
   if updating_recovery:
     # Recovery is generated as a patch using both the boot image
     # (which contains the same linux kernel as recovery) and the file
@@ -858,26 +1245,39 @@
     # For older builds where recovery-resource.dat is not present, we
     # use only the boot image as the source.
 
-    MakeRecoveryPatch(OPTIONS.target_tmp, output_zip,
-                      target_recovery, target_boot)
-    script.DeleteFiles(["/system/recovery-from-boot.p",
-                        "/system/etc/install-recovery.sh"])
+    if not target_has_recovery_patch:
+      def output_sink(fn, data):
+        common.ZipWriteStr(output_zip, "recovery/" + fn, data)
+        system_items.Get("system/" + fn, dir=False)
+
+      common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
+                               target_recovery, target_boot)
+      script.DeleteFiles(["/system/recovery-from-boot.p",
+                          "/system/etc/install-recovery.sh"])
     print "recovery image changed; including as patch from boot."
   else:
     print "recovery image unchanged; skipping."
 
   script.ShowProgress(0.1, 10)
 
-  target_symlinks = CopySystemFiles(target_zip, None)
+  target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
+  if vendor_diff:
+    target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
+
+  temp_script = script.MakeTemporary()
+  system_items.GetMetadata(target_zip)
+  system_items.Get("system").SetPermissions(temp_script)
+  if vendor_diff:
+    vendor_items.GetMetadata(target_zip)
+    vendor_items.Get("vendor").SetPermissions(temp_script)
+
+  # Note that this call will mess up the trees of Items, so make sure
+  # we're done with them.
+  source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
+  if vendor_diff:
+    source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
 
   target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
-  temp_script = script.MakeTemporary()
-  Item.GetMetadata(target_zip)
-  Item.Get("system").SetPermissions(temp_script)
-
-  # Note that this call will mess up the tree of Items, so make sure
-  # we're done with it.
-  source_symlinks = CopySystemFiles(source_zip, None)
   source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
 
   # Delete all the symlinks in source that aren't in target.  This
@@ -889,20 +1289,20 @@
       to_delete.append(link)
   script.DeleteFiles(to_delete)
 
-  if verbatim_targets:
-    script.Print("Unpacking new files...")
+  if system_diff.verbatim_targets:
+    script.Print("Unpacking new system files...")
     script.UnpackPackageDir("system", "/system")
+  if vendor_diff and vendor_diff.verbatim_targets:
+    script.Print("Unpacking new vendor files...")
+    script.UnpackPackageDir("vendor", "/vendor")
 
-  if updating_recovery:
+  if updating_recovery and not target_has_recovery_patch:
     script.Print("Unpacking new recovery...")
     script.UnpackPackageDir("recovery", "/system")
 
-  if len(renames) > 0:
-    script.Print("Renaming files...")
-
-  for src in renames:
-    print "Renaming " + src + " to " + renames[src].name
-    script.RenameFile(src, renames[src].name)
+  system_diff.EmitRenames(script)
+  if vendor_diff:
+    vendor_diff.EmitRenames(script)
 
   script.Print("Symlinks and permissions...")
 
@@ -933,10 +1333,11 @@
   # device can still come up, it appears to be the old build and will
   # get set the OTA package again to retry.
   script.Print("Patching remaining system files...")
-  for item in deferred_patch_list:
-    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)
+  system_diff.EmitDeferredPatches(script)
+
+  if OPTIONS.wipe_user_data:
+    script.Print("Erasing user data...")
+    script.FormatPartition("/data")
 
   if OPTIONS.two_step:
     script.AppendExtra("""
@@ -945,14 +1346,14 @@
 endif;
 """ % bcb_dev)
 
-  script.AddToZip(target_zip, output_zip)
+  script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
   WriteMetadata(metadata, output_zip)
 
 
 def main(argv):
 
   def option_handler(o, a):
-    if o in ("-b", "--board_config"):
+    if o == "--board_config":
       pass   # deprecated
     elif o in ("-k", "--package_key"):
       OPTIONS.package_key = a
@@ -962,6 +1363,8 @@
       OPTIONS.wipe_user_data = True
     elif o in ("-n", "--no_prereq"):
       OPTIONS.omit_prereq = True
+    elif o in ("-o", "--oem_settings"):
+      OPTIONS.oem_source = a
     elif o in ("-e", "--extra_script"):
       OPTIONS.extra_script = a
     elif o in ("-a", "--aslr_mode"):
@@ -977,14 +1380,20 @@
                          "integers are allowed." % (a, o))
     elif o in ("-2", "--two_step"):
       OPTIONS.two_step = True
-    elif o in ("--no_signing"):
+    elif o == "--no_signing":
       OPTIONS.no_signing = True
+    elif o == "--block":
+      OPTIONS.block_based = True
+    elif o in ("-b", "--binary"):
+      OPTIONS.updater_binary = a
+    elif o in ("--no_fallback_to_full",):
+      OPTIONS.fallback_to_full = False
     else:
       return False
     return True
 
   args = common.ParseOptions(argv, __doc__,
-                             extra_opts="b:k:i:d:wne:t:a:2",
+                             extra_opts="b:k:i:d:wne:t:a:2o:",
                              extra_long_opts=["board_config=",
                                               "package_key=",
                                               "incremental_from=",
@@ -995,6 +1404,10 @@
                                               "aslr_mode=",
                                               "two_step",
                                               "no_signing",
+                                              "block",
+                                              "binary=",
+                                              "oem_settings=",
+                                              "no_fallback_to_full",
                                               ],
                              extra_option_handler=option_handler)
 
@@ -1023,38 +1436,65 @@
     print "--- target info ---"
     common.DumpInfoDict(OPTIONS.info_dict)
 
+  # If the caller explicitly specified the device-specific extensions
+  # path via -s/--device_specific, use that.  Otherwise, use
+  # META/releasetools.py if it is present in the target target_files.
+  # Otherwise, take the path of the file from 'tool_extensions' in the
+  # info dict and look for that in the local filesystem, relative to
+  # the current directory.
+
   if OPTIONS.device_specific is None:
-    OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
+    from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
+    if os.path.exists(from_input):
+      print "(using device-specific extensions from target_files)"
+      OPTIONS.device_specific = from_input
+    else:
+      OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
+
   if OPTIONS.device_specific is not None:
-    OPTIONS.device_specific = os.path.normpath(OPTIONS.device_specific)
-    print "using device-specific extensions in", OPTIONS.device_specific
+    OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
 
-  if OPTIONS.no_signing:
-    output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
-  else:
-    temp_zip_file = tempfile.NamedTemporaryFile()
-    output_zip = zipfile.ZipFile(temp_zip_file, "w",
-                                 compression=zipfile.ZIP_DEFLATED)
+  while True:
 
-  if OPTIONS.incremental_source is None:
-    WriteFullOTAPackage(input_zip, output_zip)
-    if OPTIONS.package_key is None:
-      OPTIONS.package_key = OPTIONS.info_dict.get(
-          "default_system_dev_certificate",
-          "build/target/product/security/testkey")
-  else:
-    print "unzipping source target-files..."
-    OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
-    OPTIONS.target_info_dict = OPTIONS.info_dict
-    OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
-    if OPTIONS.package_key is None:
-      OPTIONS.package_key = OPTIONS.source_info_dict.get(
-          "default_system_dev_certificate",
-          "build/target/product/security/testkey")
-    if OPTIONS.verbose:
-      print "--- source info ---"
-      common.DumpInfoDict(OPTIONS.source_info_dict)
-    WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
+    if OPTIONS.no_signing:
+      if os.path.exists(args[1]): os.unlink(args[1])
+      output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
+    else:
+      temp_zip_file = tempfile.NamedTemporaryFile()
+      output_zip = zipfile.ZipFile(temp_zip_file, "w",
+                                   compression=zipfile.ZIP_DEFLATED)
+
+    if OPTIONS.incremental_source is None:
+      WriteFullOTAPackage(input_zip, output_zip)
+      if OPTIONS.package_key is None:
+        OPTIONS.package_key = OPTIONS.info_dict.get(
+            "default_system_dev_certificate",
+            "build/target/product/security/testkey")
+      break
+
+    else:
+      print "unzipping source target-files..."
+      OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
+      OPTIONS.target_info_dict = OPTIONS.info_dict
+      OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
+      if "selinux_fc" in OPTIONS.source_info_dict:
+        OPTIONS.source_info_dict["selinux_fc"] = os.path.join(OPTIONS.source_tmp, "BOOT", "RAMDISK",
+                                                              "file_contexts")
+      if OPTIONS.package_key is None:
+        OPTIONS.package_key = OPTIONS.source_info_dict.get(
+            "default_system_dev_certificate",
+            "build/target/product/security/testkey")
+      if OPTIONS.verbose:
+        print "--- source info ---"
+        common.DumpInfoDict(OPTIONS.source_info_dict)
+      try:
+        WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
+        break
+      except ValueError:
+        if not OPTIONS.fallback_to_full: raise
+        print "--- failed to build incremental; falling back to full ---"
+        OPTIONS.incremental_source = None
+        output_zip.close()
 
   output_zip.close()
 
@@ -1062,8 +1502,6 @@
     SignOutput(temp_zip_file.name, args[1])
     temp_zip_file.close()
 
-  common.Cleanup()
-
   print "done."
 
 
@@ -1076,3 +1514,5 @@
     print "   ERROR: %s" % (e,)
     print
     sys.exit(1)
+  finally:
+    common.Cleanup()
diff --git a/tools/releasetools/rangelib.py b/tools/releasetools/rangelib.py
new file mode 100644
index 0000000..7279c60
--- /dev/null
+++ b/tools/releasetools/rangelib.py
@@ -0,0 +1,243 @@
+# 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.
+
+from __future__ import print_function
+import heapq
+import itertools
+
+__all__ = ["RangeSet"]
+
+class RangeSet(object):
+  """A RangeSet represents a set of nonoverlapping ranges on the
+  integers (ie, a set of integers, but efficient when the set contains
+  lots of runs."""
+
+  def __init__(self, data=None):
+    if isinstance(data, str):
+      self._parse_internal(data)
+    elif data:
+      self.data = tuple(self._remove_pairs(data))
+    else:
+      self.data = ()
+
+  def __iter__(self):
+    for i in range(0, len(self.data), 2):
+      yield self.data[i:i+2]
+
+  def __eq__(self, other):
+    return self.data == other.data
+  def __ne__(self, other):
+    return self.data != other.data
+  def __nonzero__(self):
+    return bool(self.data)
+
+  def __str__(self):
+    if not self.data:
+      return "empty"
+    else:
+      return self.to_string()
+
+  def __repr__(self):
+    return '<RangeSet("' + self.to_string() + '")>'
+
+  @classmethod
+  def parse(cls, text):
+    """Parse a text string consisting of a space-separated list of
+    blocks and ranges, eg "10-20 30 35-40".  Ranges are interpreted to
+    include both their ends (so the above example represents 18
+    individual blocks.  Returns a RangeSet object.
+
+    If the input has all its blocks in increasing order, then returned
+    RangeSet will have an extra attribute 'monotonic' that is set to
+    True.  For example the input "10-20 30" is monotonic, but the input
+    "15-20 30 10-14" is not, even though they represent the same set
+    of blocks (and the two RangeSets will compare equal with ==).
+    """
+    return cls(text)
+
+  def _parse_internal(self, text):
+    data = []
+    last = -1
+    monotonic = True
+    for p in text.split():
+      if "-" in p:
+        s, e = p.split("-")
+        data.append(int(s))
+        data.append(int(e)+1)
+        if last <= s <= e:
+          last = e
+        else:
+          monotonic = False
+      else:
+        s = int(p)
+        data.append(s)
+        data.append(s+1)
+        if last <= s:
+          last = s+1
+        else:
+          monotonic = True
+    data.sort()
+    self.data = tuple(self._remove_pairs(data))
+    self.monotonic = monotonic
+
+  @staticmethod
+  def _remove_pairs(source):
+    last = None
+    for i in source:
+      if i == last:
+        last = None
+      else:
+        if last is not None:
+          yield last
+        last = i
+    if last is not None:
+      yield last
+
+  def to_string(self):
+    out = []
+    for i in range(0, len(self.data), 2):
+      s, e = self.data[i:i+2]
+      if e == s+1:
+        out.append(str(s))
+      else:
+        out.append(str(s) + "-" + str(e-1))
+    return " ".join(out)
+
+  def to_string_raw(self):
+    return str(len(self.data)) + "," + ",".join(str(i) for i in self.data)
+
+  def union(self, other):
+    """Return a new RangeSet representing the union of this RangeSet
+    with the argument.
+
+    >>> RangeSet("10-19 30-34").union(RangeSet("18-29"))
+    <RangeSet("10-34")>
+    >>> RangeSet("10-19 30-34").union(RangeSet("22 32"))
+    <RangeSet("10-19 22 30-34")>
+    """
+    out = []
+    z = 0
+    for p, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))),
+                            zip(other.data, itertools.cycle((+1, -1)))):
+      if (z == 0 and d == 1) or (z == 1 and d == -1):
+        out.append(p)
+      z += d
+    return RangeSet(data=out)
+
+  def intersect(self, other):
+    """Return a new RangeSet representing the intersection of this
+    RangeSet with the argument.
+
+    >>> RangeSet("10-19 30-34").intersect(RangeSet("18-32"))
+    <RangeSet("18-19 30-32")>
+    >>> RangeSet("10-19 30-34").intersect(RangeSet("22-28"))
+    <RangeSet("")>
+    """
+    out = []
+    z = 0
+    for p, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))),
+                            zip(other.data, itertools.cycle((+1, -1)))):
+      if (z == 1 and d == 1) or (z == 2 and d == -1):
+        out.append(p)
+      z += d
+    return RangeSet(data=out)
+
+  def subtract(self, other):
+    """Return a new RangeSet representing subtracting the argument
+    from this RangeSet.
+
+    >>> RangeSet("10-19 30-34").subtract(RangeSet("18-32"))
+    <RangeSet("10-17 33-34")>
+    >>> RangeSet("10-19 30-34").subtract(RangeSet("22-28"))
+    <RangeSet("10-19 30-34")>
+    """
+
+    out = []
+    z = 0
+    for p, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))),
+                            zip(other.data, itertools.cycle((-1, +1)))):
+      if (z == 0 and d == 1) or (z == 1 and d == -1):
+        out.append(p)
+      z += d
+    return RangeSet(data=out)
+
+  def overlaps(self, other):
+    """Returns true if the argument has a nonempty overlap with this
+    RangeSet.
+
+    >>> RangeSet("10-19 30-34").overlaps(RangeSet("18-32"))
+    True
+    >>> RangeSet("10-19 30-34").overlaps(RangeSet("22-28"))
+    False
+    """
+
+    # This is like intersect, but we can stop as soon as we discover the
+    # output is going to be nonempty.
+    z = 0
+    for p, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))),
+                            zip(other.data, itertools.cycle((+1, -1)))):
+      if (z == 1 and d == 1) or (z == 2 and d == -1):
+        return True
+      z += d
+    return False
+
+  def size(self):
+    """Returns the total size of the RangeSet (ie, how many integers
+    are in the set).
+
+    >>> RangeSet("10-19 30-34").size()
+    15
+    """
+
+    total = 0
+    for i, p in enumerate(self.data):
+      if i % 2:
+        total += p
+      else:
+        total -= p
+    return total
+
+  def map_within(self, other):
+    """'other' should be a subset of 'self'.  Returns a RangeSet
+    representing what 'other' would get translated to if the integers
+    of 'self' were translated down to be contiguous starting at zero.
+
+    >>> RangeSet("0-9").map_within(RangeSet("3-4"))
+    <RangeSet("3-4")>
+    >>> RangeSet("10-19").map_within(RangeSet("13-14"))
+    <RangeSet("3-4")>
+    >>> RangeSet("10-19 30-39").map_within(RangeSet("17-19 30-32"))
+    <RangeSet("7-12")>
+    >>> RangeSet("10-19 30-39").map_within(RangeSet("12-13 17-19 30-32"))
+    <RangeSet("2-3 7-12")>
+    """
+
+    out = []
+    offset = 0
+    start = None
+    for p, d in heapq.merge(zip(self.data, itertools.cycle((-5, +5))),
+                            zip(other.data, itertools.cycle((-1, +1)))):
+      if d == -5:
+        start = p
+      elif d == +5:
+        offset += p-start
+        start = None
+      else:
+        out.append(offset + p - start)
+    return RangeSet(data=out)
+
+
+if __name__ == "__main__":
+  import doctest
+  doctest.testmod()
diff --git a/tools/releasetools/sign_target_files_apks b/tools/releasetools/sign_target_files_apks
index ab24706..98d2dc1 100755
--- a/tools/releasetools/sign_target_files_apks
+++ b/tools/releasetools/sign_target_files_apks
@@ -67,8 +67,8 @@
 
 import sys
 
-if sys.hexversion < 0x02040000:
-  print >> sys.stderr, "Python 2.4 or newer is required."
+if sys.hexversion < 0x02070000:
+  print >> sys.stderr, "Python 2.7 or newer is required."
   sys.exit(1)
 
 import base64
@@ -77,10 +77,12 @@
 import errno
 import os
 import re
+import shutil
 import subprocess
 import tempfile
 import zipfile
 
+import add_img_to_target_files
 import common
 
 OPTIONS = common.OPTIONS
@@ -88,6 +90,8 @@
 OPTIONS.extra_apks = {}
 OPTIONS.key_map = {}
 OPTIONS.replace_ota_keys = False
+OPTIONS.replace_verity_public_key = False
+OPTIONS.replace_verity_private_key = False
 OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
 
 def GetApkCerts(tf_zip):
@@ -139,14 +143,49 @@
   return data
 
 
-def SignApks(input_tf_zip, output_tf_zip, apk_key_map, key_passwords):
+def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
+                       apk_key_map, key_passwords):
+
   maxsize = max([len(os.path.basename(i.filename))
                  for i in input_tf_zip.infolist()
                  if i.filename.endswith('.apk')])
+  rebuild_recovery = False
+
+  tmpdir = tempfile.mkdtemp()
+  def write_to_temp(fn, attr, data):
+    fn = os.path.join(tmpdir, fn)
+    if fn.endswith("/"):
+      fn = os.path.join(tmpdir, fn)
+      os.mkdir(fn)
+    else:
+      d = os.path.dirname(fn)
+      if d and not os.path.exists(d):
+        os.makedirs(d)
+
+      if attr >> 16 == 0xa1ff:
+        os.symlink(data, fn)
+      else:
+        with open(fn, "wb") as f:
+          f.write(data)
 
   for info in input_tf_zip.infolist():
+    if info.filename.startswith("IMAGES/"): continue
+
     data = input_tf_zip.read(info.filename)
     out_info = copy.copy(info)
+
+    if (info.filename == "META/misc_info.txt" and
+        OPTIONS.replace_verity_public_key):
+      ReplaceVerityPrivateKey(input_tf_zip, output_tf_zip, misc_info, OPTIONS.replace_verity_private_key[1])
+    elif (info.filename == "BOOT/RAMDISK/verity_key" and
+        OPTIONS.replace_verity_private_key):
+      ReplaceVerityPublicKey(output_tf_zip, OPTIONS.replace_verity_public_key[1])
+    elif (info.filename.startswith("BOOT/") or
+        info.filename.startswith("RECOVERY/") or
+        info.filename.startswith("META/") or
+        info.filename == "SYSTEM/etc/recovery-resource.dat"):
+      write_to_temp(info.filename, info.external_attr, data)
+
     if info.filename.endswith(".apk"):
       name = os.path.basename(info.filename)
       key = apk_key_map[name]
@@ -161,16 +200,51 @@
     elif info.filename in ("SYSTEM/build.prop",
                            "RECOVERY/RAMDISK/default.prop"):
       print "rewriting %s:" % (info.filename,)
-      new_data = RewriteProps(data)
+      new_data = RewriteProps(data, misc_info)
       output_tf_zip.writestr(out_info, new_data)
+      if info.filename == "RECOVERY/RAMDISK/default.prop":
+        write_to_temp(info.filename, info.external_attr, new_data)
     elif info.filename.endswith("mac_permissions.xml"):
       print "rewriting %s with new keys." % (info.filename,)
       new_data = ReplaceCerts(data)
       output_tf_zip.writestr(out_info, new_data)
+    elif info.filename in ("SYSTEM/recovery-from-boot.p",
+                           "SYSTEM/bin/install-recovery.sh"):
+      rebuild_recovery = True
+    elif (OPTIONS.replace_ota_keys and
+          info.filename in ("RECOVERY/RAMDISK/res/keys",
+                            "SYSTEM/etc/security/otacerts.zip")):
+      # don't copy these files if we're regenerating them below
+      pass
+    elif (OPTIONS.replace_verity_public_key and
+          info.filename == "META/misc_info.txt"):
+      pass
+    elif (OPTIONS.replace_verity_private_key and
+          info.filename == "BOOT/RAMDISK/verity_key"):
+      pass
     else:
       # a non-APK file; copy it verbatim
       output_tf_zip.writestr(out_info, data)
 
+  if OPTIONS.replace_ota_keys:
+    new_recovery_keys = ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
+    if new_recovery_keys:
+      write_to_temp("RECOVERY/RAMDISK/res/keys", 0755 << 16, new_recovery_keys)
+
+  if rebuild_recovery:
+    recovery_img = common.GetBootableImage(
+        "recovery.img", "recovery.img", tmpdir, "RECOVERY", info_dict=misc_info)
+    boot_img = common.GetBootableImage(
+        "boot.img", "boot.img", tmpdir, "BOOT", info_dict=misc_info)
+
+    def output_sink(fn, data):
+      output_tf_zip.writestr("SYSTEM/"+fn, data)
+
+    common.MakeRecoveryPatch(tmpdir, output_sink, recovery_img, boot_img,
+                             info_dict=misc_info)
+
+  shutil.rmtree(tmpdir)
+
 
 def ReplaceCerts(data):
   """Given a string of data, replace all occurences of a set
@@ -214,14 +288,20 @@
   return ",".join(sorted(tags))
 
 
-def RewriteProps(data):
+def RewriteProps(data, misc_info):
   output = []
   for line in data.split("\n"):
     line = line.strip()
     original_line = line
-    if line and line[0] != '#':
+    if line and line[0] != '#' and "=" in line:
       key, value = line.split("=", 1)
-      if key == "ro.build.fingerprint":
+      if (key == "ro.build.fingerprint"
+          and misc_info.get("oem_fingerprint_properties") is None):
+        pieces = value.split("/")
+        pieces[-1] = EditTags(pieces[-1])
+        value = "/".join(pieces)
+      elif (key == "ro.build.thumbprint"
+          and misc_info.get("oem_fingerprint_properties") is not None):
         pieces = value.split("/")
         pieces[-1] = EditTags(pieces[-1])
         value = "/".join(pieces)
@@ -235,7 +315,7 @@
       elif key == "ro.build.display.id":
         # change, eg, "JWR66N dev-keys" to "JWR66N"
         value = value.split()
-        if len(value) >  1 and value[-1].endswith("-keys"):
+        if len(value) > 1 and value[-1].endswith("-keys"):
           value.pop()
         value = " ".join(value)
       line = key + "=" + value
@@ -265,7 +345,8 @@
   for k in keylist:
     m = re.match(r"^(.*)\.x509\.pem$", k)
     if not m:
-      raise common.ExternalError("can't parse \"%s\" from META/otakeys.txt" % (k,))
+      raise common.ExternalError(
+          "can't parse \"%s\" from META/otakeys.txt" % (k,))
     k = m.group(1)
     mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
 
@@ -287,10 +368,11 @@
                   os.path.join(OPTIONS.search_path, "framework", "dumpkey.jar")]
                  + mapped_keys + extra_recovery_keys,
                  stdout=subprocess.PIPE)
-  data, _ = p.communicate()
+  new_recovery_keys, _ = p.communicate()
   if p.returncode != 0:
     raise common.ExternalError("failed to run dumpkeys")
-  common.ZipWriteStr(output_tf_zip, "RECOVERY/RAMDISK/res/keys", data)
+  common.ZipWriteStr(output_tf_zip, "RECOVERY/RAMDISK/res/keys",
+                     new_recovery_keys)
 
   # SystemUpdateActivity uses the x509.pem version of the keys, but
   # put into a zipfile system/etc/security/otacerts.zip.
@@ -304,6 +386,19 @@
   common.ZipWriteStr(output_tf_zip, "SYSTEM/etc/security/otacerts.zip",
                      tempfile.getvalue())
 
+  return new_recovery_keys
+
+def ReplaceVerityPublicKey(targetfile_zip, key_path):
+  print "Replacing verity public key with %s" % key_path
+  with open(key_path) as f:
+    common.ZipWriteStr(targetfile_zip, "BOOT/RAMDISK/verity_key", f.read())
+
+def ReplaceVerityPrivateKey(targetfile_input_zip, targetfile_output_zip, misc_info, key_path):
+  print "Replacing verity private key with %s" % key_path
+  current_key = misc_info["verity_key"]
+  original_misc_info = targetfile_input_zip.read("META/misc_info.txt")
+  new_misc_info = original_misc_info.replace(current_key, key_path)
+  common.ZipWriteStr(targetfile_output_zip, "META/misc_info.txt", new_misc_info)
 
 def BuildKeyMap(misc_info, key_mapping_options):
   for s, d in key_mapping_options:
@@ -347,6 +442,10 @@
           raise ValueError("Bad tag change '%s'" % (i,))
         new.append(i[0] + i[1:].strip())
       OPTIONS.tag_changes = tuple(new)
+    elif o == "--replace_verity_public_key":
+      OPTIONS.replace_verity_public_key = (True, a)
+    elif o == "--replace_verity_private_key":
+      OPTIONS.replace_verity_private_key = (True, a)
     else:
       return False
     return True
@@ -357,7 +456,9 @@
                                               "default_key_mappings=",
                                               "key_mapping=",
                                               "replace_ota_keys",
-                                              "tag_changes="],
+                                              "tag_changes=",
+                                              "replace_verity_public_key=",
+                                              "replace_verity_private_key="],
                              extra_option_handler=option_handler)
 
   if len(args) != 2:
@@ -375,14 +476,14 @@
   CheckAllApksSigned(input_zip, apk_key_map)
 
   key_passwords = common.GetKeyPasswords(set(apk_key_map.values()))
-  SignApks(input_zip, output_zip, apk_key_map, key_passwords)
-
-  if OPTIONS.replace_ota_keys:
-    ReplaceOtaKeys(input_zip, output_zip, misc_info)
+  ProcessTargetFiles(input_zip, output_zip, misc_info,
+                     apk_key_map, key_passwords)
 
   input_zip.close()
   output_zip.close()
 
+  add_img_to_target_files.AddImagesToTargetFiles(args[1])
+
   print "done."
 
 
diff --git a/tools/releasetools/sparse_img.py b/tools/releasetools/sparse_img.py
new file mode 100644
index 0000000..6b70fe1
--- /dev/null
+++ b/tools/releasetools/sparse_img.py
@@ -0,0 +1,198 @@
+# 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.
+
+import bisect
+import os
+import sys
+import struct
+import pprint
+from hashlib import sha1
+
+from rangelib import *
+
+class SparseImage(object):
+  """Wraps a sparse image file (and optional file map) into an image
+  object suitable for passing to BlockImageDiff."""
+
+  def __init__(self, simg_fn, file_map_fn=None):
+    self.simg_f = f = open(simg_fn, "rb")
+
+    header_bin = f.read(28)
+    header = struct.unpack("<I4H4I", header_bin)
+
+    magic = header[0]
+    major_version = header[1]
+    minor_version = header[2]
+    file_hdr_sz = header[3]
+    chunk_hdr_sz = header[4]
+    self.blocksize = blk_sz = header[5]
+    self.total_blocks = total_blks = header[6]
+    total_chunks = header[7]
+    image_checksum = header[8]
+
+    if magic != 0xED26FF3A:
+      raise ValueError("Magic should be 0xED26FF3A but is 0x%08X" % (magic,))
+    if major_version != 1 or minor_version != 0:
+      raise ValueError("I know about version 1.0, but this is version %u.%u" %
+                       (major_version, minor_version))
+    if file_hdr_sz != 28:
+      raise ValueError("File header size was expected to be 28, but is %u." %
+                       (file_hdr_sz,))
+    if chunk_hdr_sz != 12:
+      raise ValueError("Chunk header size was expected to be 12, but is %u." %
+                       (chunk_hdr_sz,))
+
+    print("Total of %u %u-byte output blocks in %u input chunks."
+          % (total_blks, blk_sz, total_chunks))
+
+    pos = 0   # in blocks
+    care_data = []
+    self.offset_map = offset_map = []
+
+    for i in range(total_chunks):
+      header_bin = f.read(12)
+      header = struct.unpack("<2H2I", header_bin)
+      chunk_type = header[0]
+      reserved1 = header[1]
+      chunk_sz = header[2]
+      total_sz = header[3]
+      data_sz = total_sz - 12
+
+      if chunk_type == 0xCAC1:
+        if data_sz != (chunk_sz * blk_sz):
+          raise ValueError(
+              "Raw chunk input size (%u) does not match output size (%u)" %
+              (data_sz, chunk_sz * blk_sz))
+        else:
+          care_data.append(pos)
+          care_data.append(pos + chunk_sz)
+          offset_map.append((pos, chunk_sz, f.tell()))
+          pos += chunk_sz
+          f.seek(data_sz, os.SEEK_CUR)
+
+      elif chunk_type == 0xCAC2:
+        raise ValueError("Fill chunks are not supported")
+
+      elif chunk_type == 0xCAC3:
+        if data_sz != 0:
+          raise ValueError("Don't care chunk input size is non-zero (%u)" %
+                           (data_sz))
+        else:
+          pos += chunk_sz
+
+      elif chunk_type == 0xCAC4:
+        raise ValueError("CRC32 chunks are not supported")
+
+      else:
+        raise ValueError("Unknown chunk type 0x%04X not supported" %
+                         (chunk_type,))
+
+    self.care_map = RangeSet(care_data)
+    self.offset_index = [i[0] for i in offset_map]
+
+    if file_map_fn:
+      self.LoadFileBlockMap(file_map_fn)
+    else:
+      self.file_map = {"__DATA": self.care_map}
+
+  def ReadRangeSet(self, ranges):
+    return [d for d in self._GetRangeData(ranges)]
+
+  def TotalSha1(self):
+    """Return the SHA-1 hash of all data in the 'care' regions of this image."""
+    h = sha1()
+    for d in self._GetRangeData(self.care_map):
+      h.update(d)
+    return h.hexdigest()
+
+  def _GetRangeData(self, ranges):
+    """Generator that produces all the image data in 'ranges'.  The
+    number of individual pieces returned is arbitrary (and in
+    particular is not necessarily equal to the number of ranges in
+    'ranges'.
+
+    This generator is stateful -- it depends on the open file object
+    contained in this SparseImage, so you should not try to run two
+    instances of this generator on the same object simultaneously."""
+
+    f = self.simg_f
+    for s, e in ranges:
+      to_read = e-s
+      idx = bisect.bisect_right(self.offset_index, s) - 1
+      chunk_start, chunk_len, filepos = self.offset_map[idx]
+
+      # for the first chunk we may be starting partway through it.
+      p = filepos + ((s - chunk_start) * self.blocksize)
+      remain = chunk_len - (s - chunk_start)
+
+      f.seek(p, os.SEEK_SET)
+      this_read = min(remain, to_read)
+      yield f.read(this_read * self.blocksize)
+      to_read -= this_read
+
+      while to_read > 0:
+        # continue with following chunks if this range spans multiple chunks.
+        idx += 1
+        chunk_start, chunk_len, filepos = self.offset_map[idx]
+        f.seek(filepos, os.SEEK_SET)
+        this_read = min(chunk_len, to_read)
+        yield f.read(this_read * self.blocksize)
+        to_read -= this_read
+
+  def LoadFileBlockMap(self, fn):
+    remaining = self.care_map
+    self.file_map = out = {}
+
+    with open(fn) as f:
+      for line in f:
+        fn, ranges = line.split(None, 1)
+        ranges = RangeSet.parse(ranges)
+        out[fn] = ranges
+        assert ranges.size() == ranges.intersect(remaining).size()
+        remaining = remaining.subtract(ranges)
+
+    # For all the remaining blocks in the care_map (ie, those that
+    # aren't part of the data for any file), divide them into blocks
+    # that are all zero and blocks that aren't.  (Zero blocks are
+    # handled specially because (1) there are usually a lot of them
+    # and (2) bsdiff handles files with long sequences of repeated
+    # bytes especially poorly.)
+
+    zero_blocks = []
+    nonzero_blocks = []
+    reference = '\0' * self.blocksize
+
+    f = self.simg_f
+    for s, e in remaining:
+      for b in range(s, e):
+        idx = bisect.bisect_right(self.offset_index, b) - 1
+        chunk_start, chunk_len, filepos = self.offset_map[idx]
+        filepos += (b-chunk_start) * self.blocksize
+        f.seek(filepos, os.SEEK_SET)
+        data = f.read(self.blocksize)
+
+        if data == reference:
+          zero_blocks.append(b)
+          zero_blocks.append(b+1)
+        else:
+          nonzero_blocks.append(b)
+          nonzero_blocks.append(b+1)
+
+    out["__ZERO"] = RangeSet(data=zero_blocks)
+    out["__NONZERO"] = RangeSet(data=nonzero_blocks)
+
+  def ResetFileMap(self):
+    """Throw away the file map and treat the entire image as
+    undifferentiated data."""
+    self.file_map = {"__DATA": self.care_map}
diff --git a/tools/zipalign/Android.mk b/tools/zipalign/Android.mk
index 49f9043..4194f81 100644
--- a/tools/zipalign/Android.mk
+++ b/tools/zipalign/Android.mk
@@ -12,13 +12,15 @@
 	ZipEntry.cpp \
 	ZipFile.cpp
 
-LOCAL_C_INCLUDES += external/zlib
+LOCAL_C_INCLUDES += external/zlib \
+	external/zopfli/src
 
 LOCAL_STATIC_LIBRARIES := \
 	libandroidfw \
 	libutils \
 	libcutils \
-	liblog
+	liblog \
+	libzopfli
 
 ifeq ($(HOST_OS),linux)
 LOCAL_LDLIBS += -lrt
diff --git a/tools/zipalign/ZipAlign.cpp b/tools/zipalign/ZipAlign.cpp
index 8b2d1af..dc2826b 100644
--- a/tools/zipalign/ZipAlign.cpp
+++ b/tools/zipalign/ZipAlign.cpp
@@ -32,19 +32,20 @@
     fprintf(stderr, "Zip alignment utility\n");
     fprintf(stderr, "Copyright (C) 2009 The Android Open Source Project\n\n");
     fprintf(stderr,
-        "Usage: zipalign [-f] [-v] <align> infile.zip outfile.zip\n"
+        "Usage: zipalign [-f] [-v] [-z] <align> infile.zip outfile.zip\n"
         "       zipalign -c [-v] <align> infile.zip\n\n" );
     fprintf(stderr,
         "  <align>: alignment in bytes, e.g. '4' provides 32-bit alignment\n");
     fprintf(stderr, "  -c: check alignment only (does not modify file)\n");
     fprintf(stderr, "  -f: overwrite existing outfile.zip\n");
     fprintf(stderr, "  -v: verbose output\n");
+    fprintf(stderr, "  -z: recompress using Zopfli\n");
 }
 
 /*
  * Copy all entries from "pZin" to "pZout", aligning as needed.
  */
-static int copyAndAlign(ZipFile* pZin, ZipFile* pZout, int alignment)
+static int copyAndAlign(ZipFile* pZin, ZipFile* pZout, int alignment, bool zopfli)
 {
     int numEntries = pZin->getNumEntries();
     ZipEntry* pEntry;
@@ -67,6 +68,12 @@
             //    pEntry->getFileName(), (long) pEntry->getFileOffset(),
             //    (long) pEntry->getUncompressedLen());
 
+            if (zopfli) {
+                status = pZout->addRecompress(pZin, pEntry, &pNewEntry);
+                bias += pNewEntry->getCompressedLen() - pEntry->getCompressedLen();
+            } else {
+                status = pZout->add(pZin, pEntry, padding, &pNewEntry);
+            }
         } else {
             /*
              * Copy the entry, adjusting as required.  We assume that the
@@ -79,9 +86,9 @@
             //printf("--- %s: orig at %ld(+%d) len=%ld, adding pad=%d\n",
             //    pEntry->getFileName(), (long) pEntry->getFileOffset(),
             //    bias, (long) pEntry->getUncompressedLen(), padding);
+            status = pZout->add(pZin, pEntry, padding, &pNewEntry);
         }
 
-        status = pZout->add(pZin, pEntry, padding, &pNewEntry);
         if (status != NO_ERROR)
             return 1;
         bias += padding;
@@ -98,7 +105,7 @@
  * output file exists and "force" wasn't specified.
  */
 static int process(const char* inFileName, const char* outFileName,
-    int alignment, bool force)
+    int alignment, bool force, bool zopfli)
 {
     ZipFile zin, zout;
 
@@ -129,7 +136,7 @@
         return 1;
     }
 
-    int result = copyAndAlign(&zin, &zout, alignment);
+    int result = copyAndAlign(&zin, &zout, alignment, zopfli);
     if (result != 0) {
         printf("zipalign: failed rewriting '%s' to '%s'\n",
             inFileName, outFileName);
@@ -196,6 +203,7 @@
     bool check = false;
     bool force = false;
     bool verbose = false;
+    bool zopfli = false;
     int result = 1;
     int alignment;
     char* endp;
@@ -222,6 +230,9 @@
             case 'v':
                 verbose = true;
                 break;
+            case 'z':
+                zopfli = true;
+                break;
             default:
                 fprintf(stderr, "ERROR: unknown flag -%c\n", *cp);
                 wantUsage = true;
@@ -252,7 +263,7 @@
         result = verify(argv[1], alignment, verbose);
     } else {
         /* create the new archive */
-        result = process(argv[1], argv[2], alignment, force);
+        result = process(argv[1], argv[2], alignment, force, zopfli);
 
         /* trust, but verify */
         if (result == 0)
diff --git a/tools/zipalign/ZipFile.cpp b/tools/zipalign/ZipFile.cpp
index 8057068..3c5ec15 100644
--- a/tools/zipalign/ZipFile.cpp
+++ b/tools/zipalign/ZipFile.cpp
@@ -28,6 +28,8 @@
 #include <zlib.h>
 #define DEF_MEM_LEVEL 8                // normally in zutil.h?
 
+#include "zopfli/deflate.h"
+
 #include <memory.h>
 #include <sys/stat.h>
 #include <errno.h>
@@ -638,6 +640,141 @@
 }
 
 /*
+ * Add an entry by copying it from another zip file, recompressing with
+ * Zopfli if already compressed.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+status_t ZipFile::addRecompress(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
+    ZipEntry** ppEntry)
+{
+    ZipEntry* pEntry = NULL;
+    status_t result;
+    long lfhPosn, startPosn, endPosn, uncompressedLen;
+
+    if (mReadOnly)
+        return INVALID_OPERATION;
+
+    /* make sure we're in a reasonable state */
+    assert(mZipFp != NULL);
+    assert(mEntries.size() == mEOCD.mTotalNumEntries);
+
+    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    pEntry = new ZipEntry;
+    if (pEntry == NULL) {
+        result = NO_MEMORY;
+        goto bail;
+    }
+
+    result = pEntry->initFromExternal(pSourceZip, pSourceEntry);
+    if (result != NO_ERROR)
+        goto bail;
+
+    /*
+     * From here on out, failures are more interesting.
+     */
+    mNeedCDRewrite = true;
+
+    /*
+     * Write the LFH, even though it's still mostly blank.  We need it
+     * as a place-holder.  In theory the LFH isn't necessary, but in
+     * practice some utilities demand it.
+     */
+    lfhPosn = ftell(mZipFp);
+    pEntry->mLFH.write(mZipFp);
+    startPosn = ftell(mZipFp);
+
+    /*
+     * Copy the data over.
+     *
+     * If the "has data descriptor" flag is set, we want to copy the DD
+     * fields as well.  This is a fixed-size area immediately following
+     * the data.
+     */
+    if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0)
+    {
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    uncompressedLen = pSourceEntry->getUncompressedLen();
+
+    if (pSourceEntry->isCompressed()) {
+        void *buf = pSourceZip->uncompress(pSourceEntry);
+        if (buf == NULL) {
+            result = NO_MEMORY;
+            goto bail;
+        }
+        long startPosn = ftell(mZipFp);
+        unsigned long crc;
+        if (compressFpToFp(mZipFp, NULL, buf, uncompressedLen, &crc) != NO_ERROR) {
+            ALOGW("recompress of '%s' failed\n", pEntry->mCDE.mFileName);
+            result = UNKNOWN_ERROR;
+            free(buf);
+            goto bail;
+        }
+        long endPosn = ftell(mZipFp);
+        pEntry->setDataInfo(uncompressedLen, endPosn - startPosn,
+            pSourceEntry->getCRC32(), ZipEntry::kCompressDeflated);
+        free(buf);
+    } else {
+        off_t copyLen;
+        copyLen = pSourceEntry->getCompressedLen();
+        if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0)
+            copyLen += ZipEntry::kDataDescriptorLen;
+
+        if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL)
+            != NO_ERROR)
+        {
+            ALOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName);
+            result = UNKNOWN_ERROR;
+            goto bail;
+        }
+    }
+
+    /*
+     * Update file offsets.
+     */
+    endPosn = ftell(mZipFp);
+
+    /*
+     * Success!  Fill out new values.
+     */
+    pEntry->setLFHOffset(lfhPosn);
+    mEOCD.mNumEntries++;
+    mEOCD.mTotalNumEntries++;
+    mEOCD.mCentralDirSize = 0;      // mark invalid; set by flush()
+    mEOCD.mCentralDirOffset = endPosn;
+
+    /*
+     * Go back and write the LFH.
+     */
+    if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) {
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+    pEntry->mLFH.write(mZipFp);
+
+    /*
+     * Add pEntry to the list.
+     */
+    mEntries.add(pEntry);
+    if (ppEntry != NULL)
+        *ppEntry = pEntry;
+    pEntry = NULL;
+
+    result = NO_ERROR;
+
+bail:
+    delete pEntry;
+    return result;
+}
+
+/*
  * Copy all of the bytes in "src" to "dst".
  *
  * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
@@ -744,73 +881,43 @@
     const void* data, size_t size, unsigned long* pCRC32)
 {
     status_t result = NO_ERROR;
-    const size_t kBufSize = 32768;
+    const size_t kBufSize = 1024 * 1024;
     unsigned char* inBuf = NULL;
     unsigned char* outBuf = NULL;
-    z_stream zstream;
+    size_t outSize = 0;
     bool atEof = false;     // no feof() aviailable yet
     unsigned long crc;
-    int zerr;
+    ZopfliOptions options;
+    unsigned char bp = 0;
 
-    /*
-     * Create an input buffer and an output buffer.
-     */
-    inBuf = new unsigned char[kBufSize];
-    outBuf = new unsigned char[kBufSize];
-    if (inBuf == NULL || outBuf == NULL) {
-        result = NO_MEMORY;
-        goto bail;
-    }
-
-    /*
-     * Initialize the zlib stream.
-     */
-    memset(&zstream, 0, sizeof(zstream));
-    zstream.zalloc = Z_NULL;
-    zstream.zfree = Z_NULL;
-    zstream.opaque = Z_NULL;
-    zstream.next_in = NULL;
-    zstream.avail_in = 0;
-    zstream.next_out = outBuf;
-    zstream.avail_out = kBufSize;
-    zstream.data_type = Z_UNKNOWN;
-
-    zerr = deflateInit2(&zstream, Z_BEST_COMPRESSION,
-        Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
-    if (zerr != Z_OK) {
-        result = UNKNOWN_ERROR;
-        if (zerr == Z_VERSION_ERROR) {
-            ALOGE("Installed zlib is not compatible with linked version (%s)\n",
-                ZLIB_VERSION);
-        } else {
-            ALOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr);
-        }
-        goto bail;
-    }
+    ZopfliInitOptions(&options);
 
     crc = crc32(0L, Z_NULL, 0);
 
-    /*
-     * Loop while we have data.
-     */
-    do {
-        size_t getSize;
-        int flush;
+    if (data) {
+        crc = crc32(crc, (const unsigned char*)data, size);
+        ZopfliDeflate(&options, 2, true, (const unsigned char*)data, size, &bp,
+            &outBuf, &outSize);
+    } else {
+        /*
+         * Create an input buffer and an output buffer.
+         */
+        inBuf = new unsigned char[kBufSize];
+        if (inBuf == NULL) {
+            result = NO_MEMORY;
+            goto bail;
+        }
 
-        /* only read if the input buffer is empty */
-        if (zstream.avail_in == 0 && !atEof) {
-            ALOGV("+++ reading %d bytes\n", (int)kBufSize);
-            if (data) {
-                getSize = size > kBufSize ? kBufSize : size;
-                memcpy(inBuf, data, getSize);
-                data = ((const char*)data) + getSize;
-                size -= getSize;
-            } else {
-                getSize = fread(inBuf, 1, kBufSize, srcFp);
-                if (ferror(srcFp)) {
-                    ALOGD("deflate read failed (errno=%d)\n", errno);
-                    goto z_bail;
-                }
+        /*
+         * Loop while we have data.
+         */
+        do {
+            size_t getSize;
+            getSize = fread(inBuf, 1, kBufSize, srcFp);
+            if (ferror(srcFp)) {
+                ALOGD("deflate read failed (errno=%d)\n", errno);
+                delete[] inBuf;
+                goto bail;
             }
             if (getSize < kBufSize) {
                 ALOGV("+++  got %d bytes, EOF reached\n",
@@ -819,51 +926,21 @@
             }
 
             crc = crc32(crc, inBuf, getSize);
+            ZopfliDeflate(&options, 2, atEof, inBuf, getSize, &bp, &outBuf, &outSize);
+        } while (!atEof);
+        delete[] inBuf;
+    }
 
-            zstream.next_in = inBuf;
-            zstream.avail_in = getSize;
-        }
-
-        if (atEof)
-            flush = Z_FINISH;       /* tell zlib that we're done */
-        else
-            flush = Z_NO_FLUSH;     /* more to come! */
-
-        zerr = deflate(&zstream, flush);
-        if (zerr != Z_OK && zerr != Z_STREAM_END) {
-            ALOGD("zlib deflate call failed (zerr=%d)\n", zerr);
-            result = UNKNOWN_ERROR;
-            goto z_bail;
-        }
-
-        /* write when we're full or when we're done */
-        if (zstream.avail_out == 0 ||
-            (zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize))
-        {
-            ALOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf));
-            if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) !=
-                (size_t)(zstream.next_out - outBuf))
-            {
-                ALOGD("write %d failed in deflate\n",
-                    (int) (zstream.next_out - outBuf));
-                goto z_bail;
-            }
-
-            zstream.next_out = outBuf;
-            zstream.avail_out = kBufSize;
-        }
-    } while (zerr == Z_OK);
-
-    assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
+    ALOGV("+++ writing %d bytes\n", (int)outSize);
+    if (fwrite(outBuf, 1, outSize, dstFp) != outSize) {
+        ALOGD("write %d failed in deflate\n", (int)outSize);
+        goto bail;
+    }
 
     *pCRC32 = crc;
 
-z_bail:
-    deflateEnd(&zstream);        /* free up any allocated structures */
-
 bail:
-    delete[] inBuf;
-    delete[] outBuf;
+    free(outBuf);
 
     return result;
 }
@@ -1148,7 +1225,7 @@
 #endif
 
 // free the memory when you're done
-void* ZipFile::uncompress(const ZipEntry* entry)
+void* ZipFile::uncompress(const ZipEntry* entry) const
 {
     size_t unlen = entry->getUncompressedLen();
     size_t clen = entry->getCompressedLen();
diff --git a/tools/zipalign/ZipFile.h b/tools/zipalign/ZipFile.h
index 7877550..b99cda5 100644
--- a/tools/zipalign/ZipFile.h
+++ b/tools/zipalign/ZipFile.h
@@ -127,6 +127,15 @@
         int padding, ZipEntry** ppEntry);
 
     /*
+     * Add an entry by copying it from another zip file, recompressing with
+     * Zopfli if already compressed.
+     *
+     * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+     */
+    status_t addRecompress(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
+        ZipEntry** ppEntry);
+
+    /*
      * Mark an entry as having been removed.  It is not actually deleted
      * from the archive or our internal data structures until flush() is
      * called.
@@ -147,7 +156,7 @@
      */
     //bool uncompress(const ZipEntry* pEntry, void* buf) const;
     //bool uncompress(const ZipEntry* pEntry, FILE* fp) const;
-    void* uncompress(const ZipEntry* pEntry);
+    void* uncompress(const ZipEntry* pEntry) const;
 
     /*
      * Get an entry, by name.  Returns NULL if not found.