diff --git a/apps/Development/Android.mk b/apps/Development/Android.mk
index 99133e85f..9dd2e1a34 100644
--- a/apps/Development/Android.mk
+++ b/apps/Development/Android.mk
@@ -1,7 +1,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_TAGS := optional
LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common org.apache.http.legacy
diff --git a/apps/Development/AndroidManifest.xml b/apps/Development/AndroidManifest.xml
index 3ac819077..d932174d1 100644
--- a/apps/Development/AndroidManifest.xml
+++ b/apps/Development/AndroidManifest.xml
@@ -66,6 +66,8 @@
+
+
@@ -86,8 +88,7 @@
-
+
diff --git a/build/Android.mk b/build/Android.mk
index b6445a0d7..f7dcb55f2 100644
--- a/build/Android.mk
+++ b/build/Android.mk
@@ -83,6 +83,10 @@ ALL_SDK_FILES += $(android_jar_full_target)
# ====================================================
+# The Jack & Jill compiler jars
+ALL_SDK_FILES += $(HOST_OUT)/framework/jack.jar
+ALL_SDK_FILES += $(HOST_OUT)/framework/jill.jar
+
# The uiautomator stubs
ALL_SDK_FILES += $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_uiautomator_intermediates/javalib.jar
@@ -111,13 +115,17 @@ ANDROID_SUPPORT_LIBRARIES := \
android-support-v7-gridlayout \
android-support-v7-mediarouter \
android-support-v7-palette \
+ android-support-v7-preference \
android-support-v7-recyclerview \
android-support-v13 \
+ android-support-v14-preference \
android-support-v17-leanback \
+ android-support-v17-preference-leanback \
android-support-multidex \
android-support-multidex-instrumentation \
android-support-design \
android-support-percent \
+ android-support-recommendation \
android-support-customtabs
$(foreach lib, $(ANDROID_SUPPORT_LIBRARIES), $(eval $(call _package_sdk_library,$(lib))))
diff --git a/build/build_android_stubs.mk b/build/build_android_stubs.mk
index f74d23c0f..211d4a529 100644
--- a/build/build_android_stubs.mk
+++ b/build/build_android_stubs.mk
@@ -51,5 +51,7 @@ $(full_target): $(stub_timestamp) $(framework_res_package)
$(hide) jar -cf $@ -C $(PRIVATE_CLASS_INTERMEDIATES_DIR) .
$(hide) jar -u0f $@ -C $(PRIVATE_CLASS_INTERMEDIATES_DIR) resources.arsc
-$(jack_lib) : $(full_target) $(JILL_JAR) $(JACK_JAR)
- $(transform-jar-to-jack)
\ No newline at end of file
+$(jack_lib) : $(full_target) $(JILL_JAR) $(JACK)
+ $(transform-jar-to-jack)
+
+$(call define-jar-to-toc-rule, $(full_target))
diff --git a/build/sdk-darwin-x86.atree b/build/sdk-darwin-x86.atree
index 0ed8e20f1..a8447948d 100644
--- a/build/sdk-darwin-x86.atree
+++ b/build/sdk-darwin-x86.atree
@@ -28,11 +28,11 @@ lib/libc++.dylib strip platform-tools/lib/l
# revision as specified in the source.properties.
-lib/libLLVM.dylib strip build-tools/${PLATFORM_NAME}/lib/libLLVM.dylib
-lib/libbcc.dylib strip build-tools/${PLATFORM_NAME}/lib/libbcc.dylib
-lib/libbcinfo.dylib strip build-tools/${PLATFORM_NAME}/lib/libbcinfo.dylib
-lib/libclang.dylib strip build-tools/${PLATFORM_NAME}/lib/libclang.dylib
-lib/libc++.dylib strip build-tools/${PLATFORM_NAME}/lib/libc++.dylib
+lib64/libLLVM.dylib strip build-tools/${PLATFORM_NAME}/lib64/libLLVM.dylib
+lib64/libbcc.dylib strip build-tools/${PLATFORM_NAME}/lib64/libbcc.dylib
+lib64/libbcinfo.dylib strip build-tools/${PLATFORM_NAME}/lib64/libbcinfo.dylib
+lib64/libclang.dylib strip build-tools/${PLATFORM_NAME}/lib64/libclang.dylib
+lib64/libc++.dylib strip build-tools/${PLATFORM_NAME}/lib64/libc++.dylib
prebuilts/sdk/tools/darwin/bin/arm-linux-androideabi-ld strip build-tools/${PLATFORM_NAME}/arm-linux-androideabi-ld
prebuilts/sdk/tools/darwin/bin/i686-linux-android-ld strip build-tools/${PLATFORM_NAME}/i686-linux-android-ld
diff --git a/build/sdk-linux-x86.atree b/build/sdk-linux-x86.atree
index 63dcbc35c..f18413d70 100644
--- a/build/sdk-linux-x86.atree
+++ b/build/sdk-linux-x86.atree
@@ -18,7 +18,7 @@
# Platform Tools Component
##############################################################################
-lib/libc++.so strip platform-tools/lib/libc++.so
+lib64/libc++.so strip platform-tools/lib64/libc++.so
##############################################################################
# Build Tools Component
@@ -28,11 +28,11 @@ lib/libc++.so strip platform-tools/lib/li
# revision as specified in the source.properties.
-lib/libLLVM.so strip build-tools/${PLATFORM_NAME}/lib/libLLVM.so
-lib/libbcc.so strip build-tools/${PLATFORM_NAME}/lib/libbcc.so
-lib/libbcinfo.so strip build-tools/${PLATFORM_NAME}/lib/libbcinfo.so
-lib/libclang.so strip build-tools/${PLATFORM_NAME}/lib/libclang.so
-lib/libc++.so strip build-tools/${PLATFORM_NAME}/lib/libc++.so
+lib64/libLLVM.so strip build-tools/${PLATFORM_NAME}/lib64/libLLVM.so
+lib64/libbcc.so strip build-tools/${PLATFORM_NAME}/lib64/libbcc.so
+lib64/libbcinfo.so strip build-tools/${PLATFORM_NAME}/lib64/libbcinfo.so
+lib64/libclang.so strip build-tools/${PLATFORM_NAME}/lib64/libclang.so
+lib64/libc++.so strip build-tools/${PLATFORM_NAME}/lib64/libc++.so
prebuilts/sdk/tools/linux/bin/arm-linux-androideabi-ld strip build-tools/${PLATFORM_NAME}/arm-linux-androideabi-ld
prebuilts/sdk/tools/linux/bin/i686-linux-android-ld strip build-tools/${PLATFORM_NAME}/i686-linux-android-ld
diff --git a/build/sdk-windows-x86.atree b/build/sdk-windows-x86.atree
index 9856f987c..abad00920 100644
--- a/build/sdk-windows-x86.atree
+++ b/build/sdk-windows-x86.atree
@@ -79,20 +79,20 @@ rm build-tools/${PLATFORM_NAME}/llvm-rs-cc
bin/llvm-rs-cc.exe strip build-tools/${PLATFORM_NAME}/llvm-rs-cc.exe
# libc++.so not needed on Windows.
-rm build-tools/${PLATFORM_NAME}/lib/libc++.so
+rm build-tools/${PLATFORM_NAME}/lib64/libc++.so
-rm build-tools/${PLATFORM_NAME}/lib/libLLVM.so
+rm build-tools/${PLATFORM_NAME}/lib64/libLLVM.so
lib/libLLVM.dll strip build-tools/${PLATFORM_NAME}/libLLVM.dll
-rm build-tools/${PLATFORM_NAME}/lib/libclang.so
+rm build-tools/${PLATFORM_NAME}/lib64/libclang.so
lib/libclang.dll strip build-tools/${PLATFORM_NAME}/libclang.dll
#bcc not yet compiled on windows
-rm build-tools/${PLATFORM_NAME}/lib/libbcc.so
+rm build-tools/${PLATFORM_NAME}/lib64/libbcc.so
lib/libbcc.dll strip build-tools/${PLATFORM_NAME}/libbcc.dll
-rm build-tools/${PLATFORM_NAME}/lib/libbcinfo.so
+rm build-tools/${PLATFORM_NAME}/lib64/libbcinfo.so
lib/libbcinfo.dll strip build-tools/${PLATFORM_NAME}/libbcinfo.dll
rm build-tools/${PLATFORM_NAME}/bcc_compat
diff --git a/build/sdk.atree b/build/sdk.atree
index ee1e25132..14acaaa59 100644
--- a/build/sdk.atree
+++ b/build/sdk.atree
@@ -57,19 +57,19 @@ development/sdk/generated-api-versions.xml platform-tools/api/api-versions.xm
prebuilts/sdk/sdk-annotations/annotations.zip platform-tools/api/annotations.zip
# systrace
-external/chromium-trace/agents/__init__.py platform-tools/systrace/agents/__init__.py
-external/chromium-trace/agents/atrace_agent.py platform-tools/systrace/agents/atrace_agent.py
-external/chromium-trace/systrace.py platform-tools/systrace/systrace.py
-external/chromium-trace/systrace-legacy.py platform-tools/systrace/systrace-legacy.py
-external/chromium-trace/systrace_agent.py platform-tools/systrace/systrace_agent.py
-external/chromium-trace/util.py platform-tools/systrace/util.py
-external/chromium-trace/systrace_trace_viewer.html platform-tools/systrace/systrace_trace_viewer.html
-external/chromium-trace/prefix.html platform-tools/systrace/prefix.html
-external/chromium-trace/suffix.html platform-tools/systrace/suffix.html
-external/chromium-trace/LICENSE platform-tools/systrace/LICENSE
-external/chromium-trace/AUTHORS platform-tools/systrace/AUTHORS
-external/chromium-trace/NOTICE platform-tools/systrace/NOTICE
-external/chromium-trace/UPSTREAM_REVISION platform-tools/systrace/UPSTREAM_REVISION
+external/chromium-trace/catapult/systrace/systrace/agents/__init__.py platform-tools/systrace/agents/__init__.py
+external/chromium-trace/catapult/systrace/systrace/agents/atrace_agent.py platform-tools/systrace/agents/atrace_agent.py
+external/chromium-trace/catapult/systrace/systrace/systrace.py platform-tools/systrace/systrace.py
+external/chromium-trace/catapult/systrace/systrace/systrace-legacy.py platform-tools/systrace/systrace-legacy.py
+external/chromium-trace/catapult/systrace/systrace/systrace_agent.py platform-tools/systrace/systrace_agent.py
+external/chromium-trace/catapult/systrace/systrace/util.py platform-tools/systrace/util.py
+external/chromium-trace/catapult/systrace/systrace/prefix.html platform-tools/systrace/prefix.html
+external/chromium-trace/catapult/systrace/systrace/suffix.html platform-tools/systrace/suffix.html
+external/chromium-trace/catapult/systrace/systrace/LICENSE platform-tools/systrace/LICENSE
+external/chromium-trace/catapult/systrace/systrace/AUTHORS platform-tools/systrace/AUTHORS
+external/chromium-trace/systrace_trace_viewer.html platform-tools/systrace/systrace_trace_viewer.html
+external/chromium-trace/NOTICE platform-tools/systrace/NOTICE
+external/chromium-trace/UPSTREAM_REVISION platform-tools/systrace/UPSTREAM_REVISION
##############################################################################
# Build Tools Component
@@ -129,10 +129,12 @@ bin/dexdump build-tools/${PLATFORM_NAME}/dexdu
# multi-dex
prebuilts/sdk/tools/lib/shrinkedAndroid.jar build-tools/${PLATFORM_NAME}/lib/shrinkedAndroid.jar
-prebuilts/sdk/tools/jack.jar build-tools/${PLATFORM_NAME}/jack.jar
-prebuilts/sdk/tools/jill.jar build-tools/${PLATFORM_NAME}/jill.jar
dalvik/dx/etc/mainDexClasses.rules build-tools/${PLATFORM_NAME}/mainDexClasses.rules
+# Jack & Jill
+${HOST_OUT}/framework/jack.jar build-tools/${PLATFORM_NAME}/jack.jar
+${HOST_OUT}/framework/jill.jar build-tools/${PLATFORM_NAME}/jill.jar
+
##############################################################################
# Platform Component
@@ -521,6 +523,22 @@ ${OUT_DIR}/target/common/obj/PACKAGING/android-support-percent_intermediates/and
frameworks/support/customtabs/AndroidManifest.xml extras/android/support/customtabs/AndroidManifest.xml
${OUT_DIR}/target/common/obj/PACKAGING/android-support-customtabs_intermediates/android-support-customtabs.jar extras/android/support/customtabs/libs/android-support-customtabs.jar
+
+frameworks/support/v7/preference/AndroidManifest.xml extras/android/support/v7/preference/AndroidManifest.xml
+frameworks/support/v7/preference/res extras/android/support/v7/preference/res
+${OUT_DIR}/target/common/obj/PACKAGING/android-support-v7-preference_intermediates/android-support-v7-preference.jar extras/android/support/v7/preference/libs/android-support-v7-preference.jar
+
+frameworks/support/v14/preference/AndroidManifest.xml extras/android/support/v14/preference/AndroidManifest.xml
+frameworks/support/v14/preference/res extras/android/support/v14/preference/res
+${OUT_DIR}/target/common/obj/PACKAGING/android-support-v14-preference_intermediates/android-support-v14-preference.jar extras/android/support/v14/preference/libs/android-support-v14-preference.jar
+
+frameworks/support/v17/preference-leanback/AndroidManifest.xml extras/android/support/v17/preference-leanback/AndroidManifest.xml
+frameworks/support/v17/preference-leanback/res extras/android/support/v17/preference-leanback/res
+${OUT_DIR}/target/common/obj/PACKAGING/android-support-v17-preference-leanback_intermediates/android-support-v17-preference-leanback.jar extras/android/support/v17/preference-leanback/libs/android-support-v17-preference-leanback.jar
+
+frameworks/support/recommendation/AndroidManifest.xml extras/android/support/recommendation/AndroidManifest.xml
+${OUT_DIR}/target/common/obj/PACKAGING/android-support-recommendation_intermediates/android-support-recommendation.jar extras/android/support/recommendation/libs/android-support-recommendation.jar
+
##############################################################################
# Tests Component
##############################################################################
diff --git a/build/tools/windows_sdk.mk b/build/tools/windows_sdk.mk
index 9b97a19a4..7d586a8c4 100644
--- a/build/tools/windows_sdk.mk
+++ b/build/tools/windows_sdk.mk
@@ -11,13 +11,10 @@
# This way we avoid the headache of building a full SDK in MinGW mode, which is
# made complicated by the fact the build system does not support cross-compilation.
-# We can only use this under Linux with the mingw32 package installed.
+# We can only use this under Linux
ifneq ($(shell uname),Linux)
$(error Linux is required to create a Windows SDK)
endif
-ifeq ($(strip $(shell which i586-mingw32msvc-gcc 2>/dev/null)),)
-$(error MinGW is required to build a Windows SDK. Please 'apt-get install mingw32')
-endif
ifeq ($(strip $(shell which unix2dos todos 2>/dev/null)),)
$(error Need a unix2dos command. Please 'apt-get install tofrodos')
endif
@@ -34,26 +31,18 @@ WIN_TARGETS := \
aapt adb aidl \
aprotoc \
bcc_compat \
+ clang \
etc1tool \
dexdump dmtracedump \
fastboot \
hprof-conv \
llvm-rs-cc \
- prebuilt \
sqlite3 \
zipalign \
split-select \
$(WIN_SDK_TARGETS)
-# This is the list of *Linux* build tools that we need
-# in order to be able to make the WIN_TARGETS. They are
-# build prerequisites.
-WIN_BUILD_PREREQ := \
- acp \
- llvm-tblgen \
- clang-tblgen \
- $(WIN_SDK_BUILD_PREREQ)
-
+WIN_TARGETS := $(foreach t,$(WIN_TARGETS),$(ALL_MODULES.host_cross_$(t).INSTALLED))
# MAIN_SDK_NAME/DIR is set in build/core/Makefile
WIN_SDK_NAME := $(subst $(HOST_OS)-$(SDK_HOST_ARCH),windows,$(MAIN_SDK_NAME))
@@ -80,11 +69,10 @@ endef
win_sdk: $(WIN_SDK_ZIP)
$(call winsdk-banner,Done)
-winsdk-tools: $(WIN_BUILD_PREREQ)
- $(call winsdk-banner,Build Windows Tools)
- $(hide) USE_MINGW=1 USE_CCACHE="" $(MAKE) PRODUCT-$(TARGET_PRODUCT)-$(strip $(WIN_TARGETS)) $(if $(hide),,showcommands)
+winsdk-tools: $(WIN_TARGETS)
+ $(call winsdk-banner,Tools Done)
-$(WIN_SDK_ZIP): winsdk-tools sdk
+$(WIN_SDK_ZIP): $(WIN_TARGETS) $(INTERNAL_SDK_TARGET)
$(call winsdk-banner,Build $(WIN_SDK_NAME))
$(call winsdk-info)
$(hide) rm -rf $(WIN_SDK_DIR)
diff --git a/build/windows_sdk_whitelist.mk b/build/windows_sdk_whitelist.mk
deleted file mode 100644
index bf04360f0..000000000
--- a/build/windows_sdk_whitelist.mk
+++ /dev/null
@@ -1,83 +0,0 @@
-# Whitelist of SDK projects that can be built for the SDK on Windows
-
-# The Windows SDK cannot build all the projects from the SDK tree, typically
-# due to obvious compiler/architectures differences. When building the Windows
-# SDK, we only care about a subset of projects (e.g. generally the SDK tools
-# and a few platform-specific binaries.)
-#
-# This file defines a whitelist of projects that can be built in the Windows
-# SDK case. Note that whitelisting a project directory will NOT actually build
-# it -- it will only allow one to reference it as a make dependency.
-#
-# This file is included by build/core/main.mk.
-
-# Note that there are 2 flavors of this file:
-#
-# - The other file: sdk/build/windows_sdk_whitelist.mk
-# must list all projects that are that are NOT specific to a given platform.
-# These binaries are the ones typically found in the SDK/tools directory.
-#
-# - This file: development/build/windows_sdk_whitelist.mk
-# must list all projects that are specific to a given platform. These
-# projects generate files that are generally locates in SDK/platform-tools,
-# or SDK/platforms/, etc.
-
-# -----
-# Whitelist of platform specific projects that do NOT need Java (e.g. C libraries)
-
-subdirs += \
- prebuilt \
- prebuilts \
- build/libs/host \
- build/tools/zipalign \
- dalvik/dexdump \
- dalvik/libdex \
- dalvik/tools/dmtracedump \
- dalvik/tools/hprof-conv \
- development/host \
- development/tools/etc1tool \
- development/tools/line_endings \
- external/clang \
- external/easymock \
- external/expat \
- external/gtest \
- external/libcxx \
- external/libcxxabi \
- external/compiler-rt \
- external/libpng \
- external/llvm \
- external/protobuf \
- external/sqlite/dist \
- external/zlib \
- external/zopfli \
- frameworks/base \
- frameworks/compile \
- frameworks/native \
- frameworks/rs \
- frameworks/tools \
- system/core/adb \
- system/core/base \
- system/core/fastboot \
- system/core/libcutils \
- system/core/liblog \
- system/core/libsparse \
- system/core/libziparchive \
- system/core/libutils \
- system/extras/ext4_utils
-
-# -----
-# Whitelist of platform specific projects that DO require Java
-
-ifneq (,$(shell which javac 2>/dev/null))
-subdirs += \
- build/tools/signapk \
- dalvik/dx \
- libcore \
- development/apps \
- development/tools/mkstubs \
- frameworks/compile/libbcc \
- packages
-
-else
-$(warning SDK_ONLY: javac not available.)
-endif
diff --git a/host/windows/.gitignore b/host/windows/.gitignore
index 434a0faf9..0b5cf3137 100755
--- a/host/windows/.gitignore
+++ b/host/windows/.gitignore
@@ -6,7 +6,10 @@ usb/Debug
usb/Release
usb/api/obj*
usb/api/*.log
+usb/api/*.wrn
usb/adb_winapi_test/obj*
usb/adb_winapi_test/*.log
+usb/adb_winapi_test/*.wrn
usb/winusb/obj*
-usb/winusb/*.log
\ No newline at end of file
+usb/winusb/*.log
+usb/winusb/*.wrn
diff --git a/host/windows/prebuilt/usb/AdbWinApi.def b/host/windows/prebuilt/usb/AdbWinApi.def
deleted file mode 100644
index 18941481b..000000000
--- a/host/windows/prebuilt/usb/AdbWinApi.def
+++ /dev/null
@@ -1,15 +0,0 @@
-LIBRARY AdbWinApi.dll
-EXPORTS
-AdbEnumInterfaces
-AdbNextInterface
-AdbCreateInterfaceByName
-AdbOpenDefaultBulkReadEndpoint
-AdbOpenDefaultBulkWriteEndpoint
-AdbCloseHandle
-AdbGetInterfaceName
-AdbWriteEndpointSync
-AdbReadEndpointSync
-AdbGetSerialNumber
-AdbGetUsbInterfaceDescriptor
-AdbGetUsbDeviceDescriptor
-AdbGetEndpointInformation
diff --git a/host/windows/prebuilt/usb/AdbWinApi.dll b/host/windows/prebuilt/usb/AdbWinApi.dll
index b5586eb50..7abe26cf1 100755
Binary files a/host/windows/prebuilt/usb/AdbWinApi.dll and b/host/windows/prebuilt/usb/AdbWinApi.dll differ
diff --git a/host/windows/prebuilt/usb/AdbWinApi.pdb b/host/windows/prebuilt/usb/AdbWinApi.pdb
new file mode 100755
index 000000000..233518bb3
Binary files /dev/null and b/host/windows/prebuilt/usb/AdbWinApi.pdb differ
diff --git a/host/windows/prebuilt/usb/AdbWinUsbApi.dll b/host/windows/prebuilt/usb/AdbWinUsbApi.dll
index 0c9e00bd9..e7a6de120 100755
Binary files a/host/windows/prebuilt/usb/AdbWinUsbApi.dll and b/host/windows/prebuilt/usb/AdbWinUsbApi.dll differ
diff --git a/host/windows/prebuilt/usb/AdbWinUsbApi.pdb b/host/windows/prebuilt/usb/AdbWinUsbApi.pdb
new file mode 100755
index 000000000..0883ebf60
Binary files /dev/null and b/host/windows/prebuilt/usb/AdbWinUsbApi.pdb differ
diff --git a/host/windows/prebuilt/usb/Android.mk b/host/windows/prebuilt/usb/Android.mk
index e8af1678b..f1da6b915 100644
--- a/host/windows/prebuilt/usb/Android.mk
+++ b/host/windows/prebuilt/usb/Android.mk
@@ -7,6 +7,7 @@ LOCAL_MODULE_CLASS := STATIC_LIBRARIES
LOCAL_SRC_FILES_x86 := AdbWinApi.a
LOCAL_MODULE_SUFFIX := .a
LOCAL_MULTILIB := 32
+LOCAL_MODULE_HOST_OS := windows
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
@@ -16,6 +17,7 @@ LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_SRC_FILES_x86 := AdbWinApi.dll
LOCAL_MODULE_SUFFIX := .dll
LOCAL_MULTILIB := 32
+LOCAL_MODULE_HOST_OS := windows
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
@@ -25,4 +27,5 @@ LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_SRC_FILES_x86 := AdbWinUsbApi.dll
LOCAL_MODULE_SUFFIX := .dll
LOCAL_MULTILIB := 32
+LOCAL_MODULE_HOST_OS := windows
include $(BUILD_PREBUILT)
diff --git a/host/windows/usb/adb_winapi_test/BUILDME.TXT b/host/windows/usb/adb_winapi_test/BUILDME.TXT
index 9365b5855..f53fee293 100755
--- a/host/windows/usb/adb_winapi_test/BUILDME.TXT
+++ b/host/windows/usb/adb_winapi_test/BUILDME.TXT
@@ -12,8 +12,31 @@ 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.
-In order to build adb_winapi_test.dll you will need to install Windows Driver
-Kit, which can be obtained from Microsoft. Assuming that WDK is installed, you
-need to set one of the WDK's build environments, "cd" back into this directory,
-and execute "build -cbeEIFZ" to clean and rebuild this project, or you can
-execute "build -befEIF" to do a minimal build.
+In order to build a directory with a SOURCES file you will need to install
+the Windows Driver Kit, which can be obtained from Microsoft:
+
+Windows Driver Kit Version 7.1.0
+https://www.microsoft.com/en-us/download/details.aspx?id=11800
+md5: 8fe981a1706d43ad34bda496e6558f94
+sha1: de6abdb8eb4e08942add4aa270c763ed4e3d8242
+
+This old version is used because it can build for Windows Vista (WDK 8.1
+cannot), it includes compilers (so it doesn't require Visual Studio), and it is
+probably not too far from the WDK that this code was originally built with, so
+it should be less risky.
+
+When installing the WDK, uncheck `Device Simulation Framework' because it is
+unnecessary and it installs a kernel-mode driver that we don't need.
+
+Assuming that WDK is installed, you need to set one of the WDK's build
+environments (Start Menu -> Windows Driver Kits -> x86 Free Build Environment;
+choose the one for the oldest version of Windows you want to support),
+"cd" back into this directory, and execute "build -cbeEIFZ" to clean and rebuild
+this project, or you can execute "build -befEIF" to do a minimal build.
+
+Note that you need to build AdbWinApi.dll (..\api) before you build
+this directory, as this depends on the AdbWinApi.lib import library.
+
+When you're done with the WDK build environment, don't forget to right-click the
+OACR icon (in the lower-right notification area of the taskbar) and choose
+`Close'.
diff --git a/host/windows/usb/adb_winapi_test/SOURCES b/host/windows/usb/adb_winapi_test/SOURCES
index ec82dee3f..3663ecb43 100755
--- a/host/windows/usb/adb_winapi_test/SOURCES
+++ b/host/windows/usb/adb_winapi_test/SOURCES
@@ -18,12 +18,17 @@ TARGETNAME = adb_winapi_test
TARGETPATH = obj
TARGETTYPE = PROGRAM
+_NT_TARGET_VERSION = $(_NT_TARGET_VERSION_VISTA)
+
UMTYPE = console
UMENTRY = main
# Use statically linked atl libraries:
USE_STATIC_ATL = 1
+# Use STL, default version
+USE_STL = 1
+
# Use multithreaded libraries
USE_LIBCMT = 1
@@ -34,13 +39,19 @@ TARGETLIBS=$(SDK_LIB_PATH)\ole32.lib \
INCLUDES=$(DDK_INC_PATH)\;$(SDK_INC_PATH)\;$(CRT_INC_PATH)\;$(ATL_INC_PATH)\api
# Common C defines
-USER_C_FLAGS = $(USER_C_FLAGS) /FD /wd4100 /nologo
+USER_C_FLAGS = $(USER_C_FLAGS) /FD /wd4100 /nologo
-# Turn on all warnings, and treat warnings as errors
-MSC_WARNING_LEVEL = /W4 /Wp64 /WX
+# The STL uses C++ exception handling.
+USE_NATIVE_EH=1
-PRECOMPILED_CXX = 1
-PRECOMPILED_INCLUDE = stdafx.h
-PRECOMPILED_SOURCEFILE = stdafx.cpp
+# Turn on all warnings, and treat warnings as errors
+MSC_WARNING_LEVEL = /W4 /WX
+
+# Disable precompiled header to work-around compiler issue with interaction with
+# ASLR on Windows 7 and newer.
+# http://blogs.msdn.com/b/vcblog/archive/2009/11/12/visual-c-precompiled-header-errors-on-windows-7.aspx
+#PRECOMPILED_CXX = 1
+#PRECOMPILED_INCLUDE = stdafx.h
+#PRECOMPILED_SOURCEFILE = stdafx.cpp
SOURCES = adb_winapi_test.cpp
diff --git a/host/windows/usb/adb_winapi_test/adb_winapi_test.cpp b/host/windows/usb/adb_winapi_test/adb_winapi_test.cpp
index 11fcadf01..75bf76a82 100755
--- a/host/windows/usb/adb_winapi_test/adb_winapi_test.cpp
+++ b/host/windows/usb/adb_winapi_test/adb_winapi_test.cpp
@@ -33,24 +33,35 @@ const GUID kAdbInterfaceId = ANDROID_USB_CLASS_ID;
int interface_count = 0;
// Constants used to initialize a "handshake" message
-#define MAX_PAYLOAD 4096
-#define A_SYNC 0x434e5953
-#define A_CNXN 0x4e584e43
-#define A_OPEN 0x4e45504f
-#define A_OKAY 0x59414b4f
-#define A_CLSE 0x45534c43
-#define A_WRTE 0x45545257
-#define A_VERSION 0x01000000
+#define MAX_PAYLOAD 4096
+#define A_SYNC 0x434e5953
+#define A_CNXN 0x4e584e43
+#define A_OPEN 0x4e45504f
+#define A_OKAY 0x59414b4f
+#define A_CLSE 0x45534c43
+#define A_WRTE 0x45545257
+#define A_AUTH 0x48545541
+#define A_VERSION 0x01000000
+
+// AUTH packets first argument
+#define ADB_AUTH_TOKEN 1
+#define ADB_AUTH_SIGNATURE 2
+#define ADB_AUTH_RSAPUBLICKEY 3
+
+// Interface descriptor constants for ADB interface
+#define ADB_CLASS 0xff
+#define ADB_SUBCLASS 0x42
+#define ADB_PROTOCOL 0x1
// Formats message sent to USB device
-struct message {
- unsigned int command; /* command identifier constant */
- unsigned int arg0; /* first argument */
- unsigned int arg1; /* second argument */
- unsigned int data_length; /* length of payload (0 is allowed) */
- unsigned int data_crc32; /* crc32 of data payload */
- unsigned int magic; /* command ^ 0xffffffff */
-};
+struct message {
+ unsigned int command; /* command identifier constant */
+ unsigned int arg0; /* first argument */
+ unsigned int arg1; /* second argument */
+ unsigned int data_length; /* length of payload (0 is allowed) */
+ unsigned int data_crc32; /* crc32 of data payload */
+ unsigned int magic; /* command ^ 0xffffffff */
+};
//
// Test routines declarations.
@@ -69,7 +80,11 @@ bool TestInterface(const wchar_t* device_name);
bool TestInterfaceHandle(ADBAPIHANDLE interface_handle);
// Sends a "handshake" message to the given interface.
-bool DeviceHandShake(ADBAPIHANDLE adb_interface);
+bool DeviceHandShake(ADBAPIHANDLE adb_interface);
+
+// Test AdbCloseHandle race condition.
+bool TestCloseRaceCondition();
+
int __cdecl _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) {
// Test enum interfaces.
if (!TestEnumInterfaces())
@@ -85,6 +100,10 @@ int __cdecl _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) {
if (!TestInterfaces())
return -2;
+ // Test for AdbCloseHandle race condition
+ if (!TestCloseRaceCondition())
+ return -3;
+
return 0;
}
@@ -119,52 +138,60 @@ bool TestEnumInterfaces() {
if (interface_info.flags & SPINT_REMOVED)
printf(" REMOVED");
- buf_size = sizeof(buf);;
- };
+ buf_size = sizeof(buf);
+ }
- AdbCloseHandle(enum_handle);
- return true;
+ bool ret = true;
+ if (GetLastError() != ERROR_NO_MORE_ITEMS) {
+ printf("\n--- AdbNextInterface failure %u", GetLastError());
+ ret = false;
+ }
+
+ if (!AdbCloseHandle(enum_handle)) {
+ printf("\n--- AdbCloseHandle failure %u", GetLastError());
+ ret = false;
+ }
+
+ return ret;
}
bool TestInterfaces() {
+ bool ret = true;
+
// Enumerate interfaces
ADBAPIHANDLE enum_handle =
AdbEnumInterfaces(kAdbInterfaceId, true, true, true);
if (NULL == enum_handle) {
printf("\nTest interfaces failure:");
printf("\nUnable to enumerate ADB interfaces: %u", GetLastError());
- return false;
- }
-
- // Unite interface info structure and buffer big enough to contain the
- // largest structure.
- union {
- AdbInterfaceInfo interface_info;
- char buf[4096];
- };
- unsigned long buf_size = sizeof(buf);
-
- // Test each found interface
- while (AdbNextInterface(enum_handle, &interface_info, &buf_size)) {
- TestInterface(interface_info.device_name);
- buf_size = sizeof(buf);
- };
+ ret = false;
+ } else {
+ // Unite interface info structure and buffer big enough to contain the
+ // largest structure.
+ union {
+ AdbInterfaceInfo interface_info;
+ char buf[4096];
+ };
+ unsigned long buf_size = sizeof(buf);
+
+ // Test each found interface
+ while (AdbNextInterface(enum_handle, &interface_info, &buf_size)) {
+ TestInterface(interface_info.device_name);
+ buf_size = sizeof(buf);
+ }
- AdbCloseHandle(enum_handle);
+ if (GetLastError() != ERROR_NO_MORE_ITEMS) {
+ printf("\n--- AdbNextInterface failure %u", GetLastError());
+ ret = false;
+ }
- // Create interface by VID/PID/MI
- ADBAPIHANDLE interface_handle =
- AdbCreateInterface(kAdbInterfaceId, DEVICE_VENDOR_ID,
- DEVICE_COMPOSITE_PRODUCT_ID, DEVICE_INTERFACE_ID);
- if (NULL == interface_handle) {
- printf("\nUnable to create interface by VID/PID: %u", GetLastError());
- return false;
+ if (!AdbCloseHandle(enum_handle)) {
+ printf("\n--- AdbCloseHandle failure %u", GetLastError());
+ ret = false;
+ }
}
- // Test it
- TestInterfaceHandle(interface_handle);
- AdbCloseHandle(interface_handle);
- return true;
+ return ret;
}
bool TestInterface(const wchar_t* device_name) {
@@ -179,18 +206,98 @@ bool TestInterface(const wchar_t* device_name) {
// Test it
TestInterfaceHandle(interface_handle);
- AdbCloseHandle(interface_handle);
+ if (!AdbCloseHandle(interface_handle)) {
+ printf("\n--- AdbCloseHandle failure %u", GetLastError());
+ return false;
+ }
+
return true;
}
+bool TestInterfaceName(ADBAPIHANDLE interface_handle) {
+ bool ret = true;
+ unsigned long intr_name_size = 0;
+ char* buf = NULL;
+
+ if (AdbGetInterfaceName(interface_handle, NULL, &intr_name_size, true)) {
+ printf("\n--- AdbGetInterfaceName unexpectedly succeeded %u",
+ GetLastError());
+ ret = false;
+ goto exit;
+ }
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ printf("\n--- AdbGetInterfaceName failure %u", GetLastError());
+ ret = false;
+ goto exit;
+ }
+ if (intr_name_size == 0) {
+ printf("\n--- AdbGetInterfaceName returned name size of zero");
+ ret = false;
+ goto exit;
+ }
+
+ const size_t buf_size = intr_name_size + 16; // extra in case of overwrite
+ buf = reinterpret_cast(malloc(buf_size));
+ if (buf == NULL) {
+ printf("\n--- could not malloc %d bytes, errno %u", buf_size, errno);
+ ret = false;
+ goto exit;
+ }
+ const char buf_fill = (unsigned char)0xFF;
+ memset(buf, buf_fill, buf_size);
+
+ if (!AdbGetInterfaceName(interface_handle, buf, &intr_name_size, true)) {
+ printf("\n--- AdbGetInterfaceName failure %u", GetLastError());
+ ret = false;
+ goto exit;
+ }
+ if (buf[intr_name_size - 1] != '\0') {
+ printf("\n--- AdbGetInterfaceName returned non-NULL terminated string");
+ ret = false;
+ goto exit;
+ }
+ for (size_t i = intr_name_size; i < buf_size; ++i) {
+ if (buf[i] != buf_fill) {
+ printf("\n--- AdbGetInterfaceName overwrote past the end of the buffer at"
+ " index %u with 0x%02X", i, (unsigned char)buf[i]);
+ ret = false;
+ goto exit;
+ }
+ }
+
+ printf("\n+++ Interface name %s", buf);
+
+exit:
+ free(buf);
+
+ return ret;
+}
+
+void DumpEndpointInformation(const AdbEndpointInformation* pipe_info) {
+ printf("\n max_packet_size = %u", pipe_info->max_packet_size);
+ printf("\n max_transfer_size = %u", pipe_info->max_transfer_size);
+ printf("\n endpoint_type = %u", pipe_info->endpoint_type);
+ const char* endpoint_type_desc = NULL;
+ switch (pipe_info->endpoint_type) {
+#define CASE_TYPE(type) case type: endpoint_type_desc = #type; break
+ CASE_TYPE(AdbEndpointTypeInvalid);
+ CASE_TYPE(AdbEndpointTypeControl);
+ CASE_TYPE(AdbEndpointTypeIsochronous);
+ CASE_TYPE(AdbEndpointTypeBulk);
+ CASE_TYPE(AdbEndpointTypeInterrupt);
+#undef CASE_TYPE
+ }
+ if (endpoint_type_desc != NULL) {
+ printf(" (%s)", endpoint_type_desc);
+ }
+ printf("\n endpoint_address = %02X", pipe_info->endpoint_address);
+ printf("\n polling_interval = %u", pipe_info->polling_interval);
+ printf("\n setting_index = %u", pipe_info->setting_index);
+}
+
bool TestInterfaceHandle(ADBAPIHANDLE interface_handle) {
// Get interface name.
- char intr_name[4096];
- unsigned long intr_name_size = sizeof(intr_name);
- if (AdbGetInterfaceName(interface_handle, intr_name, &intr_name_size, true)) {
- printf("\n+++ Interface name %s", intr_name);
- } else {
- printf("\n--- AdbGetInterfaceName failure %u", GetLastError());
+ if (!TestInterfaceName(interface_handle)) {
return false;
}
@@ -211,7 +318,7 @@ bool TestInterfaceHandle(ADBAPIHANDLE interface_handle) {
printf("\n iManufacturer = %u", dev_desc.iManufacturer);
printf("\n iProduct = %u", dev_desc.iProduct);
printf("\n iSerialNumber = %u", dev_desc.iSerialNumber);
- printf("\n bNumConfigurations = %u", dev_desc.bDescriptorType);
+ printf("\n bNumConfigurations = %u", dev_desc.bNumConfigurations);
} else {
printf("\n--- AdbGetUsbDeviceDescriptor failure %u", GetLastError());
return false;
@@ -253,8 +360,17 @@ bool TestInterfaceHandle(ADBAPIHANDLE interface_handle) {
printf("\n bAlternateSetting = %u", intr_desc.bAlternateSetting);
printf("\n bNumEndpoints = %u", intr_desc.bNumEndpoints);
printf("\n bInterfaceClass = %u", intr_desc.bInterfaceClass);
+ if (intr_desc.bInterfaceClass == ADB_CLASS) {
+ printf(" (ADB_CLASS)");
+ }
printf("\n bInterfaceSubClass = %u", intr_desc.bInterfaceSubClass);
+ if (intr_desc.bInterfaceSubClass == ADB_SUBCLASS) {
+ printf(" (ADB_SUBCLASS)");
+ }
printf("\n bInterfaceProtocol = %u", intr_desc.bInterfaceProtocol);
+ if (intr_desc.bInterfaceProtocol == ADB_PROTOCOL) {
+ printf(" (ADB_PROTOCOL)");
+ }
printf("\n iInterface = %u", intr_desc.iInterface);
} else {
printf("\n--- AdbGetUsbInterfaceDescriptor failure %u", GetLastError());
@@ -266,14 +382,10 @@ bool TestInterfaceHandle(ADBAPIHANDLE interface_handle) {
for (UCHAR pipe = 0; pipe < intr_desc.bNumEndpoints; pipe++) {
if (AdbGetEndpointInformation(interface_handle, pipe, &pipe_info)) {
printf("\n PIPE %u info:", pipe);
- printf("\n max_packet_size = %u", pipe_info.max_packet_size);
- printf("\n max_transfer_size = %u", pipe_info.max_transfer_size);
- printf("\n endpoint_type = %u", pipe_info.endpoint_type);
- printf("\n endpoint_address = %02X", pipe_info.endpoint_address);
- printf("\n polling_interval = %u", pipe_info.polling_interval);
- printf("\n setting_index = %u", pipe_info.setting_index);
+ DumpEndpointInformation(&pipe_info);
} else {
- printf("\n--- AdbGetEndpointInformation(%u) failure %u", pipe, GetLastError());
+ printf("\n--- AdbGetEndpointInformation(%u) failure %u", pipe,
+ GetLastError());
return false;
}
}
@@ -281,28 +393,20 @@ bool TestInterfaceHandle(ADBAPIHANDLE interface_handle) {
// Get default bulk read endpoint info
if (AdbGetDefaultBulkReadEndpointInformation(interface_handle, &pipe_info)) {
printf("\n Default Bulk Read Pipe info:");
- printf("\n max_packet_size = %u", pipe_info.max_packet_size);
- printf("\n max_transfer_size = %u", pipe_info.max_transfer_size);
- printf("\n endpoint_type = %u", pipe_info.endpoint_type);
- printf("\n endpoint_address = %02X", pipe_info.endpoint_address);
- printf("\n polling_interval = %u", pipe_info.polling_interval);
- printf("\n setting_index = %u", pipe_info.setting_index);
+ DumpEndpointInformation(&pipe_info);
} else {
- printf("\n--- AdbGetDefaultBulkReadEndpointInformation failure %u", GetLastError());
+ printf("\n--- AdbGetDefaultBulkReadEndpointInformation failure %u",
+ GetLastError());
return false;
}
// Get default bulk write endpoint info
if (AdbGetDefaultBulkWriteEndpointInformation(interface_handle, &pipe_info)) {
printf("\n Default Bulk Write Pipe info:");
- printf("\n max_packet_size = %u", pipe_info.max_packet_size);
- printf("\n max_transfer_size = %u", pipe_info.max_transfer_size);
- printf("\n endpoint_type = %u", pipe_info.endpoint_type);
- printf("\n endpoint_address = %02X", pipe_info.endpoint_address);
- printf("\n polling_interval = %u", pipe_info.polling_interval);
- printf("\n setting_index = %u", pipe_info.setting_index);
+ DumpEndpointInformation(&pipe_info);
} else {
- printf("\n--- AdbGetDefaultBulkWriteEndpointInformation failure %u", GetLastError());
+ printf("\n--- AdbGetDefaultBulkWriteEndpointInformation failure %u",
+ GetLastError());
return false;
}
@@ -312,6 +416,48 @@ bool TestInterfaceHandle(ADBAPIHANDLE interface_handle) {
return true;
}
+void HexDump(const void* data, const size_t read_bytes) {
+ const unsigned char* buf = reinterpret_cast(data);
+ const size_t line_length = 16;
+ for (size_t n = 0; n < read_bytes; n += line_length) {
+ const unsigned char* line = &buf[n];
+ const size_t max_line = min(line_length, read_bytes - n);
+
+ printf("\n ");
+ for (size_t i = 0; i < line_length; ++i) {
+ if (i >= max_line) {
+ printf(" ");
+ } else {
+ printf("%02X ", line[i]);
+ }
+ }
+ printf(" ");
+ for (size_t i = 0; i < max_line; ++i) {
+ if (isprint(line[i])) {
+ printf("%c", line[i]);
+ } else {
+ printf(".");
+ }
+ }
+ }
+}
+
+void DumpMessageArg0(unsigned int command, unsigned int arg0) {
+ if (command == A_AUTH) {
+ const char* desc = NULL;
+ switch (arg0) {
+#define CASE_ARG0(arg) case arg: desc = # arg; break
+ CASE_ARG0(ADB_AUTH_TOKEN);
+ CASE_ARG0(ADB_AUTH_SIGNATURE);
+ CASE_ARG0(ADB_AUTH_RSAPUBLICKEY);
+#undef CASE_ARG0
+ }
+ if (desc != NULL) {
+ printf(" (%s)", desc);
+ }
+ }
+}
+
bool DeviceHandShake(ADBAPIHANDLE adb_interface) {
// Get interface name
char interf_name[512];
@@ -361,11 +507,11 @@ bool DeviceHandShake(ADBAPIHANDLE adb_interface) {
// Send connect message
message msg_send;
msg_send.command = A_CNXN;
- msg_send.arg0 = A_VERSION;
- msg_send.arg1 = MAX_PAYLOAD;
- msg_send.data_length = 0;
- msg_send.data_crc32 = 0;
- msg_send.magic = msg_send.command ^ 0xffffffff;
+ msg_send.arg0 = A_VERSION;
+ msg_send.arg1 = MAX_PAYLOAD;
+ msg_send.data_length = 0;
+ msg_send.data_crc32 = 0;
+ msg_send.magic = msg_send.command ^ 0xffffffff;
ULONG written_bytes = 0;
bool write_res = AdbWriteEndpointSync(adb_write, &msg_send, sizeof(msg_send), &written_bytes, 500);
@@ -392,10 +538,13 @@ bool DeviceHandShake(ADBAPIHANDLE adb_interface) {
printf("\n command = %08X (%c%c%c%c)", msg_rcv.command,
cmd_ansi[0], cmd_ansi[1], cmd_ansi[2], cmd_ansi[3]);
printf("\n arg0 = %08X", msg_rcv.arg0);
+ DumpMessageArg0(msg_rcv.command, msg_rcv.arg0);
printf("\n arg1 = %08X", msg_rcv.arg1);
printf("\n data_length = %u", msg_rcv.data_length);
printf("\n data_crc32 = %08X", msg_rcv.data_crc32);
printf("\n magic = %08X", msg_rcv.magic);
+ printf(" (%s)", (msg_rcv.magic == (msg_rcv.command ^ 0xffffffff)) ?
+ "valid" : "invalid");
if (0 != msg_rcv.data_length) {
char* buf = reinterpret_cast(malloc(msg_rcv.data_length));
@@ -408,19 +557,261 @@ bool DeviceHandShake(ADBAPIHANDLE adb_interface) {
return false;
}
- for (ULONG n = 0; n < read_bytes; n++) {
- if (0 == (n % 16))
- printf("\n ");
- printf("%02X ", buf[n]);
+ HexDump(buf, read_bytes);
+
+ free(buf);
+ }
+
+ if (!AdbCloseHandle(adb_write)) {
+ printf("\n--- AdbCloseHandle failure %u", GetLastError());
+ }
+ if (!AdbCloseHandle(adb_read)) {
+ printf("\n--- AdbCloseHandle failure %u", GetLastError());
+ }
+
+ return true;
+}
+
+// Randomly delay the current thread.
+class RandomDelayer {
+public:
+ // Prepare for a call to Delay() by getting random data. This call might grab
+ // locks, causing serialization, so this should be called before
+ // time-sensitive code.
+ void SeedRandom() {
+ r_ = rand();
+ }
+
+ // Randomly delay the current thread based on a previous call to SeedRandom().
+ void Delay() {
+ switch (r_ % 5) {
+ case 0:
+ Sleep(0); // Give up time slice to another read-to-run thread.
+ break;
+ case 1:
+ // Try to sleep for 1 ms, but probably more based on OS scheduler
+ // minimum granularity.
+ Sleep(1);
+ break;
+ case 2:
+ // Yield to another thread ready-to-run on the current processor.
+ SwitchToThread();
+ break;
+ case 3:
+ // Busy-wait for a random amount of time.
+ for (int i = 0; i < r_; ++i) {
+ GetLastError();
+ }
+ break;
+ case 4:
+ break; // Do nothing, no delay.
}
+ }
+
+private:
+ int r_;
+};
- printf("\n %s", buf);
+volatile ADBAPIHANDLE g_read_handle;
+volatile ADBAPIHANDLE g_interface_handle;
+volatile bool g_stop_close_race_thread;
- delete buf;
+unsigned __stdcall CloseRaceThread(void*) {
+ RandomDelayer r;
+
+ while (!g_stop_close_race_thread) {
+ r.SeedRandom();
+
+ // Do volatile reads of both globals
+ ADBAPIHANDLE read_handle = g_read_handle;
+ ADBAPIHANDLE interface_handle = g_interface_handle;
+
+ // If we got both handles, close them and clear the globals
+ if (read_handle != NULL && interface_handle != NULL) {
+ // Delay random amount before calling the API that conflicts with
+ // Adb{Read,Write}EndpointSync().
+ r.Delay();
+
+ if (!AdbCloseHandle(read_handle)) {
+ printf("\nAdbCloseHandle(read) failure: %u", GetLastError());
+ }
+ if (!AdbCloseHandle(interface_handle)) {
+ printf("\nAdbCloseHandle(interface) failure: %u", GetLastError());
+ }
+
+ // Clear globals so that read thread is free to set them.
+ g_read_handle = NULL;
+ g_interface_handle = NULL;
+ }
}
+ return 0;
+}
- AdbCloseHandle(adb_write);
- AdbCloseHandle(adb_read);
+#define EXPECTED_ERROR_LIST(FOR_EACH) \
+ FOR_EACH(ERROR_INVALID_HANDLE) \
+ FOR_EACH(ERROR_HANDLES_CLOSED) \
+ FOR_EACH(ERROR_OPERATION_ABORTED)
+
+#define MAKE_ARRAY_ITEM(x) x,
+const DWORD g_expected_errors[] = {
+ EXPECTED_ERROR_LIST(MAKE_ARRAY_ITEM)
+};
+#undef MAKE_ARRAY_ITEM
+
+#define MAKE_STRING_ITEM(x) #x,
+const char* g_expected_error_strings[] = {
+ EXPECTED_ERROR_LIST(MAKE_STRING_ITEM)
+};
+#undef MAKE_STRING_ITEM
+
+std::string get_error_description(const DWORD err) {
+ const DWORD* end = g_expected_errors + ARRAYSIZE(g_expected_errors);
+ const DWORD* found = std::find(g_expected_errors, end, err);
+ if (found != end) {
+ return g_expected_error_strings[found - g_expected_errors];
+ } else {
+ char buf[64];
+ _snprintf(buf, sizeof(buf), "%u", err);
+ return std::string(buf);
+ }
+}
- return true;
+bool is_expected_error(const DWORD err) {
+ const DWORD* end = g_expected_errors + ARRAYSIZE(g_expected_errors);
+ return std::find(g_expected_errors, end, err) != end;
+}
+
+// Test to reproduce https://code.google.com/p/android/issues/detail?id=161890
+bool TestCloseRaceCondition() {
+ const DWORD test_duration_sec = 10;
+ printf("\nTesting close race condition for %u seconds... ",
+ test_duration_sec);
+
+ ADBAPIHANDLE enum_handle =
+ AdbEnumInterfaces(kAdbInterfaceId, true, true, true);
+ if (NULL == enum_handle) {
+ printf("\nUnable to enumerate ADB interfaces: %u", GetLastError());
+ return false;
+ }
+
+ union {
+ AdbInterfaceInfo interface_info;
+ char buf[4096];
+ };
+ unsigned long buf_size = sizeof(buf);
+
+ // Get the first interface
+ if (!AdbNextInterface(enum_handle, &interface_info, &buf_size)) {
+ printf("\n--- AdbNextInterface failure %u", GetLastError());
+ return false;
+ }
+
+ if (!AdbCloseHandle(enum_handle)) {
+ printf("\nAdbCloseHandle(enum_handle) failure: %u", GetLastError());
+ }
+
+ HANDLE thread_handle = reinterpret_cast(
+ _beginthreadex(NULL, 0, CloseRaceThread, NULL, 0, NULL));
+ if (thread_handle == NULL) {
+ printf("\n--- _beginthreadex failure %u", errno);
+ return false;
+ }
+
+ // Run the test for 10 seconds. It usually reproduces the crash in 1 second.
+ const DWORD tick_start = GetTickCount();
+ const DWORD test_duration_ticks = test_duration_sec * 1000;
+ RandomDelayer r;
+
+ std::map read_errors;
+
+ while (GetTickCount() < tick_start + test_duration_ticks) {
+ // Busy-wait until close thread has cleared the handles, so that we don't
+ // leak handles during the test.
+ while (g_read_handle != NULL) {}
+ while (g_interface_handle != NULL) {}
+
+ ADBAPIHANDLE interface_handle = AdbCreateInterfaceByName(
+ interface_info.device_name);
+ if (interface_handle == NULL) {
+ // Not really expected to encounter an error here.
+ printf("\n--- AdbCreateInterfaceByName failure %u", GetLastError());
+ continue; // try again
+ }
+ ADBAPIHANDLE read_handle = AdbOpenDefaultBulkReadEndpoint(
+ interface_handle, AdbOpenAccessTypeReadWrite,
+ AdbOpenSharingModeReadWrite);
+ if (read_handle == NULL) {
+ // Not really expected to encounter an error here, so report, cleanup,
+ // and retry.
+ printf("\n--- AdbOpenDefaultBulkReadEndpoint failure %u", GetLastError());
+ AdbCloseHandle(interface_handle);
+ continue;
+ }
+
+ r.SeedRandom();
+
+ // Set handles to allow other thread to close them.
+ g_read_handle = read_handle;
+ g_interface_handle = interface_handle;
+
+ // Delay random amount before calling the API that conflicts with
+ // AdbCloseHandle().
+ r.Delay();
+
+ message msg_rcv;
+ ULONG read_bytes = 0;
+
+ while (AdbReadEndpointSync(read_handle, &msg_rcv, sizeof(msg_rcv),
+ &read_bytes, 0 /* infinite timeout */)) {
+ // Keep reading until a crash or we're broken out of the read
+ // (with an error) by the CloseRaceThread.
+ }
+ read_errors[GetLastError()]++;
+ }
+
+ g_stop_close_race_thread = true;
+ if (WaitForSingleObject(thread_handle, INFINITE) != WAIT_OBJECT_0) {
+ printf("\n--- WaitForSingleObject failure %u", GetLastError());
+ }
+ if (!CloseHandle(thread_handle)) {
+ printf("\n--- CloseHandle failure %u", GetLastError());
+ }
+
+ // The expected errors are the errors that would be encountered if the code
+ // had all the major concurrent interleavings. So the test only passes if
+ // we encountered all the expected errors, and thus stress tested all the
+ // possible major concurrent interleavings.
+ bool pass = true;
+ for (size_t i = 0; i < ARRAYSIZE(g_expected_errors); ++i) {
+ // If we didn't encounter the expected error code, then the test failed.
+ if (read_errors.count(g_expected_errors[i]) == 0) {
+ pass = false;
+ break;
+ }
+ }
+
+ if (pass) {
+ printf("passed");
+ } else {
+ printf("failed.");
+ printf("\nPerhaps you just need to run the test longer or again.");
+ }
+
+ printf("\nRead Error Code\t\tCount");
+ printf("\n=============================");
+
+ for (std::map::iterator it = read_errors.begin();
+ it != read_errors.end(); ++it) {
+ printf("\n%s\t%u%s", get_error_description(it->first).c_str(), it->second,
+ is_expected_error(it->first) ? " (expected)" : "");
+ }
+
+ for (size_t i = 0; i < ARRAYSIZE(g_expected_errors); ++i) {
+ if (read_errors.count(g_expected_errors[i]) == 0) {
+ printf("\n%s\t%u (was not encountered, but was expected)",
+ get_error_description(g_expected_errors[i]).c_str(), 0);
+ }
+ }
+
+ return pass;
}
diff --git a/host/windows/usb/adb_winapi_test/stdafx.h b/host/windows/usb/adb_winapi_test/stdafx.h
index 2aa99100a..41f6bdb5f 100755
--- a/host/windows/usb/adb_winapi_test/stdafx.h
+++ b/host/windows/usb/adb_winapi_test/stdafx.h
@@ -49,6 +49,9 @@
#include
#include
+#include
+#include
+
+
+
+
+
+
+
@@ -367,6 +375,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/Support4Demos/res/drawable-hdpi/ic_favorite.png b/samples/Support4Demos/res/drawable-hdpi/ic_favorite.png
new file mode 100644
index 000000000..1de4e583d
Binary files /dev/null and b/samples/Support4Demos/res/drawable-hdpi/ic_favorite.png differ
diff --git a/samples/Support4Demos/res/drawable-mdpi/ic_favorite.png b/samples/Support4Demos/res/drawable-mdpi/ic_favorite.png
new file mode 100644
index 000000000..aa5d340db
Binary files /dev/null and b/samples/Support4Demos/res/drawable-mdpi/ic_favorite.png differ
diff --git a/samples/Support4Demos/res/drawable-xhdpi/ic_favorite.png b/samples/Support4Demos/res/drawable-xhdpi/ic_favorite.png
new file mode 100644
index 000000000..5868c34bf
Binary files /dev/null and b/samples/Support4Demos/res/drawable-xhdpi/ic_favorite.png differ
diff --git a/samples/Support4Demos/res/drawable-xxhdpi/ic_favorite.png b/samples/Support4Demos/res/drawable-xxhdpi/ic_favorite.png
new file mode 100644
index 000000000..02b46e3bd
Binary files /dev/null and b/samples/Support4Demos/res/drawable-xxhdpi/ic_favorite.png differ
diff --git a/samples/Support4Demos/res/drawable-xxxhdpi/ic_favorite.png b/samples/Support4Demos/res/drawable-xxxhdpi/ic_favorite.png
new file mode 100644
index 000000000..d7684c4cf
Binary files /dev/null and b/samples/Support4Demos/res/drawable-xxxhdpi/ic_favorite.png differ
diff --git a/samples/Support4Demos/res/layout/drawable_compat.xml b/samples/Support4Demos/res/layout/drawable_compat.xml
new file mode 100644
index 000000000..dbf0413c9
--- /dev/null
+++ b/samples/Support4Demos/res/layout/drawable_compat.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/Support4Demos/res/layout/drawer_layout.xml b/samples/Support4Demos/res/layout/drawer_layout.xml
index 375c8027a..496bd88d5 100644
--- a/samples/Support4Demos/res/layout/drawer_layout.xml
+++ b/samples/Support4Demos/res/layout/drawer_layout.xml
@@ -24,7 +24,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
+ space available using match_parent in both dimensions. Note that
+ this child does not specify android:layout_gravity attribute. -->
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/Support4Demos/res/layout/view_pager_tab.xml b/samples/Support4Demos/res/layout/view_pager_tab.xml
new file mode 100644
index 000000000..1d0bf31ae
--- /dev/null
+++ b/samples/Support4Demos/res/layout/view_pager_tab.xml
@@ -0,0 +1,21 @@
+
+
+
+
diff --git a/samples/Support4Demos/res/values/strings.xml b/samples/Support4Demos/res/values/strings.xml
index 0c388b2b8..8917c667d 100644
--- a/samples/Support4Demos/res/values/strings.xml
+++ b/samples/Support4Demos/res/values/strings.xml
@@ -191,4 +191,13 @@
regular
round
+ Not tint
+ Color tint
+ Color state list
+
+
+ View/View pager
+ Smooth scroll
+ Switch tabs
+ Double-switch tabs
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/graphics/DrawableCompatActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/graphics/DrawableCompatActivity.java
new file mode 100644
index 000000000..f6790679b
--- /dev/null
+++ b/samples/Support4Demos/src/com/example/android/supportv4/graphics/DrawableCompatActivity.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.supportv4.graphics;
+
+import com.example.android.supportv4.R;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.graphics.drawable.DrawableCompat;
+import android.widget.ImageView;
+import android.widget.RadioGroup;
+
+/**
+ * Demonstrates use of a {@link DrawableCompat}'s ability to become circular.
+ */
+public class DrawableCompatActivity extends Activity {
+
+ private static final int IMAGE_RES = R.drawable.ic_favorite;
+
+ private ImageView mImageView;
+ private Drawable mDrawable;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.drawable_compat);
+
+ mImageView = (ImageView) findViewById(R.id.image);
+
+ Drawable d = ContextCompat.getDrawable(this, IMAGE_RES);
+ mDrawable = DrawableCompat.wrap(d.mutate());
+
+ mImageView.setImageDrawable(mDrawable);
+
+ RadioGroup rg = (RadioGroup) findViewById(R.id.drawable_compat_options);
+ rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(RadioGroup radioGroup, int id) {
+ switch (id) {
+ case R.id.drawable_compat_no_tint:
+ clearTint();
+ break;
+ case R.id.drawable_compat_color:
+ setColorTint();
+ break;
+ case R.id.drawable_compat_state_list:
+ setColorStateListTint();
+ break;
+ }
+ }
+ });
+ }
+
+ private void clearTint() {
+ DrawableCompat.setTintList(mDrawable, null);
+ }
+
+ private void setColorTint() {
+ DrawableCompat.setTint(mDrawable, Color.MAGENTA);
+ }
+
+ private void setColorStateListTint() {
+ DrawableCompat.setTintList(mDrawable,
+ ContextCompat.getColorStateList(this, R.color.tint_state_list));
+ }
+
+}
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/view/ViewPagerActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/view/ViewPagerActivity.java
new file mode 100644
index 000000000..e50cc610a
--- /dev/null
+++ b/samples/Support4Demos/src/com/example/android/supportv4/view/ViewPagerActivity.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.example.android.supportv4.view;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentStatePagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.TextView;
+import android.widget.Toast;
+import com.example.android.supportv4.R;
+
+import java.lang.Override;
+import java.lang.Runnable;
+
+public class ViewPagerActivity extends FragmentActivity {
+ private static int[] PAGE_COLORS = { 0xFF700000, 0xFF500020, 0xFF300030, 0xFF200050,
+ 0xFF000070};
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.view_pager_sample);
+
+ final ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager);
+ viewPager.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) {
+ @Override
+ public int getCount() {
+ return PAGE_COLORS.length;
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return "Page " + position;
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ Fragment fragment = new DemoObjectFragment();
+ Bundle args = new Bundle();
+ args.putInt(DemoObjectFragment.ARG_INDEX, position);
+ fragment.setArguments(args);
+ return fragment;
+ }
+ });
+
+ final CheckBox smoothScroll = (CheckBox) findViewById(R.id.view_pager_smooth_scroll);
+
+ Button switchTabsButton = (Button) findViewById(R.id.view_pager_switch_tabs_button);
+ switchTabsButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ viewPager.setCurrentItem(2, smoothScroll.isChecked());
+ Toast.makeText(view.getContext(), "Current item = " + viewPager.getCurrentItem(),
+ Toast.LENGTH_SHORT).show();
+ }
+ });
+
+ Button doubleSwitchTabsButton =
+ (Button) findViewById(R.id.view_pager_double_switch_tabs_button);
+ doubleSwitchTabsButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ viewPager.setCurrentItem(0, smoothScroll.isChecked());
+ viewPager.setCurrentItem(2, smoothScroll.isChecked());
+ Toast.makeText(view.getContext(), "Current item = " + viewPager.getCurrentItem(),
+ Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
+ public static class DemoObjectFragment extends Fragment {
+ public static final String ARG_INDEX = "index";
+
+ @Override
+ public View onCreateView(LayoutInflater inflater,
+ ViewGroup container, Bundle savedInstanceState) {
+ // The last two arguments ensure LayoutParams are inflated
+ // properly.
+ View rootView = inflater.inflate(R.layout.view_pager_tab, container, false);
+ Bundle args = getArguments();
+ int position = args.getInt(ARG_INDEX);
+ rootView.setBackgroundColor(PAGE_COLORS[position]);
+ ((TextView) rootView).setText(Integer.toString(position));
+ return rootView;
+ }
+ }
+}
diff --git a/samples/Support7Demos/AndroidManifest.xml b/samples/Support7Demos/AndroidManifest.xml
index 288b124e8..1b8850772 100644
--- a/samples/Support7Demos/AndroidManifest.xml
+++ b/samples/Support7Demos/AndroidManifest.xml
@@ -60,8 +60,9 @@
+ android:theme="@style/Theme.SampleMediaRouter">
@@ -69,8 +70,9 @@
+ android:theme="@style/Theme.SampleMediaRouter.Light">
@@ -78,8 +80,9 @@
+ android:theme="@style/Theme.SampleMediaRouter.Light.DarkActionBar">
diff --git a/samples/Support7Demos/res/drawable-hdpi/ic_android.png b/samples/Support7Demos/res/drawable-hdpi/ic_android.png
new file mode 100755
index 000000000..94b8fb1fa
Binary files /dev/null and b/samples/Support7Demos/res/drawable-hdpi/ic_android.png differ
diff --git a/samples/Support7Demos/res/drawable-mdpi/ic_android.png b/samples/Support7Demos/res/drawable-mdpi/ic_android.png
new file mode 100755
index 000000000..afc43dbdd
Binary files /dev/null and b/samples/Support7Demos/res/drawable-mdpi/ic_android.png differ
diff --git a/samples/Support7Demos/res/layout/animated_recycler_view.xml b/samples/Support7Demos/res/layout/animated_recycler_view.xml
index 29a23e26a..e5ff03760 100644
--- a/samples/Support7Demos/res/layout/animated_recycler_view.xml
+++ b/samples/Support7Demos/res/layout/animated_recycler_view.xml
@@ -26,9 +26,9 @@
android:layout_height="wrap_content"/>
diff --git a/samples/Support7Demos/res/layout/sample_media_router.xml b/samples/Support7Demos/res/layout/sample_media_router.xml
index e2f7008df..618a8e40f 100644
--- a/samples/Support7Demos/res/layout/sample_media_router.xml
+++ b/samples/Support7Demos/res/layout/sample_media_router.xml
@@ -76,6 +76,12 @@
+
-
-
-
-
-
-
-
-
+ android:layout_height="wrap_content"/>
\ No newline at end of file
diff --git a/samples/Support7Demos/res/values/strings.xml b/samples/Support7Demos/res/values/strings.xml
index accf739d1..d0b97f1cc 100644
--- a/samples/Support7Demos/res/values/strings.xml
+++ b/samples/Support7Demos/res/values/strings.xml
@@ -27,6 +27,9 @@
Play on...
Sample route settings
+ Use default media control
+ My Media Control
+
Library
Playlist
Route Info
@@ -36,6 +39,8 @@
Variable Volume (Basic) Remote Playback Route
Variable Volume (Queuing) Remote Playback Route
Variable Volume (Session) Remote Playback Route
+ Variable Volume Route Group
+ Mixed Volume Route Group
Sample route from Support7Demos
@@ -155,7 +160,7 @@
Stack From End
Animate
Predictive
- Change Anims
+ In Place Change
Add
Del
A+D
diff --git a/samples/Support7Demos/res/values/styles.xml b/samples/Support7Demos/res/values/styles.xml
index 26a9f70de..a78893826 100644
--- a/samples/Support7Demos/res/values/styles.xml
+++ b/samples/Support7Demos/res/values/styles.xml
@@ -29,8 +29,41 @@
- #ffff00
+
+
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java b/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
index b3c14c26b..b62f76e93 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
@@ -20,15 +20,12 @@
import android.app.Presentation;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.res.Resources;
import android.graphics.Bitmap;
import android.media.MediaPlayer;
-import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
-import android.support.v4.media.session.MediaSessionCompat;
import android.support.v7.media.MediaRouter.RouteInfo;
import android.support.v7.media.MediaItemStatus;
import android.util.Log;
@@ -59,6 +56,7 @@ public abstract class LocalPlayer extends Player implements
private final Context mContext;
private final Handler mHandler = new Handler();
+ private final Handler mUpdateSurfaceHandler = new Handler(mHandler.getLooper());
private MediaPlayer mMediaPlayer;
private int mState = STATE_IDLE;
private int mSeekToPos;
@@ -104,11 +102,6 @@ public void release() {
}
}
- @Override
- public MediaSessionCompat getMediaSession() {
- return mMediaSession;
- }
-
// Player
@Override
public void play(final PlaylistItem item) {
@@ -145,7 +138,8 @@ public void seek(final PlaylistItem item) {
if (mState == STATE_PLAYING || mState == STATE_PAUSED) {
mMediaPlayer.seekTo(pos);
mSeekToPos = pos;
- } else if (mState == STATE_IDLE || mState == STATE_PLAY_PENDING) {
+ } else if (mState == STATE_IDLE || mState == STATE_PREPARING_FOR_PLAY
+ || mState == STATE_PREPARING_FOR_PAUSE) {
// Seek before onPrepared() arrives,
// need to performed delayed seek in onPrepared()
mSeekToPos = pos;
@@ -175,6 +169,8 @@ public void pause() {
if (mState == STATE_PLAYING) {
mMediaPlayer.pause();
mState = STATE_PAUSED;
+ } else if (mState == STATE_PREPARING_FOR_PLAY) {
+ mState = STATE_PREPARING_FOR_PAUSE;
}
}
@@ -186,8 +182,8 @@ public void resume() {
if (mState == STATE_READY || mState == STATE_PAUSED) {
mMediaPlayer.start();
mState = STATE_PLAYING;
- } else if (mState == STATE_IDLE){
- mState = STATE_PLAY_PENDING;
+ } else if (mState == STATE_IDLE || mState == STATE_PREPARING_FOR_PAUSE) {
+ mState = STATE_PREPARING_FOR_PLAY;
}
}
@@ -224,8 +220,10 @@ public void run() {
if (mState == STATE_IDLE) {
mState = STATE_READY;
updateVideoRect();
- } else if (mState == STATE_PLAY_PENDING) {
- mState = STATE_PLAYING;
+ } else if (mState == STATE_PREPARING_FOR_PLAY
+ || mState == STATE_PREPARING_FOR_PAUSE) {
+ int prevState = mState;
+ mState = mState == STATE_PREPARING_FOR_PLAY ? STATE_PLAYING : STATE_PAUSED;
updateVideoRect();
if (mSeekToPos > 0) {
if (DEBUG) {
@@ -233,7 +231,9 @@ public void run() {
}
mMediaPlayer.seekTo(mSeekToPos);
}
- mMediaPlayer.start();
+ if (prevState == STATE_PREPARING_FOR_PLAY) {
+ mMediaPlayer.start();
+ }
}
if (mCallback != null) {
mCallback.onPlaylistChanged();
@@ -294,6 +294,7 @@ public void run() {
protected MediaPlayer getMediaPlayer() { return mMediaPlayer; }
protected int getVideoWidth() { return mVideoWidth; }
protected int getVideoHeight() { return mVideoHeight; }
+ protected int getState() { return mState; }
protected void setSurface(Surface surface) {
mSurface = surface;
mSurfaceHolder = null;
@@ -313,23 +314,29 @@ protected void removeSurface(SurfaceHolder surfaceHolder) {
}
protected void updateSurface() {
- if (mMediaPlayer == null) {
- // just return if media player is already gone
- return;
- }
- if (mSurface != null) {
- // The setSurface API does not exist until V14+.
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- ICSMediaPlayer.setSurface(mMediaPlayer, mSurface);
- } else {
- throw new UnsupportedOperationException("MediaPlayer does not support "
- + "setSurface() on this version of the platform.");
+ mUpdateSurfaceHandler.removeCallbacksAndMessages(null);
+ mUpdateSurfaceHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mMediaPlayer == null) {
+ // just return if media player is already gone
+ return;
+ }
+ if (mSurface != null) {
+ // The setSurface API does not exist until V14+.
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ ICSMediaPlayer.setSurface(mMediaPlayer, mSurface);
+ } else {
+ throw new UnsupportedOperationException("MediaPlayer does not support "
+ + "setSurface() on this version of the platform.");
+ }
+ } else if (mSurfaceHolder != null) {
+ mMediaPlayer.setDisplay(mSurfaceHolder);
+ } else {
+ mMediaPlayer.setDisplay(null);
+ }
}
- } else if (mSurfaceHolder != null) {
- mMediaPlayer.setDisplay(mSurfaceHolder);
- } else {
- mMediaPlayer.setDisplay(null);
- }
+ });
}
protected abstract void updateSize();
@@ -351,7 +358,8 @@ private void reset() {
}
private void updateVideoRect() {
- if (mState != STATE_IDLE && mState != STATE_PLAY_PENDING) {
+ if (mState != STATE_IDLE && mState != STATE_PREPARING_FOR_PLAY
+ && mState != STATE_PREPARING_FOR_PAUSE) {
int width = mMediaPlayer.getVideoWidth();
int height = mMediaPlayer.getVideoHeight();
if (width > 0 && height > 0) {
@@ -632,7 +640,10 @@ public void onWindowDestroyed() {
@Override
public Bitmap getSnapshot() {
- return mOverlay.getSnapshot();
+ if (getState() == STATE_PLAYING || getState() == STATE_PAUSED) {
+ return mOverlay.getSnapshot();
+ }
+ return null;
}
}
}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/MyMediaRouteControllerDialog.java b/samples/Support7Demos/src/com/example/android/supportv7/media/MyMediaRouteControllerDialog.java
new file mode 100644
index 000000000..326467174
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/MyMediaRouteControllerDialog.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.supportv7.media;
+
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.v7.app.MediaRouteControllerDialog;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.TextView;
+import com.example.android.supportv7.R;
+
+/**
+ * An example MediaRouteControllerDialog for demonstrating
+ * {@link android.support.v7.app.MediaRouteControllerDialog#onCreateMediaControlView}.
+ */
+public class MyMediaRouteControllerDialog extends MediaRouteControllerDialog {
+ public MyMediaRouteControllerDialog(Context context) {
+ super(context);
+ }
+
+ @Override
+ public View onCreateMediaControlView(Bundle savedInstanceState) {
+ TextView view = new TextView(getContext());
+ view.setText(R.string.my_media_control_text);
+ view.setBackgroundColor(Color.GRAY);
+ return view;
+ }
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/OverlayDisplayWindow.java b/samples/Support7Demos/src/com/example/android/supportv7/media/OverlayDisplayWindow.java
index 80cc77d9a..1d4aaa12d 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/OverlayDisplayWindow.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/OverlayDisplayWindow.java
@@ -19,7 +19,6 @@
import android.content.Context;
import android.graphics.Bitmap;
-import android.graphics.Point;
import android.graphics.SurfaceTexture;
import android.hardware.display.DisplayManager;
import android.os.Build;
@@ -95,9 +94,9 @@ public Context getContext() {
// Watches for significant changes in the overlay display window lifecycle.
public interface OverlayWindowListener {
- public void onWindowCreated(Surface surface);
- public void onWindowCreated(SurfaceHolder surfaceHolder);
- public void onWindowDestroyed();
+ void onWindowCreated(Surface surface);
+ void onWindowCreated(SurfaceHolder surfaceHolder);
+ void onWindowDestroyed();
}
/**
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java b/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
index fcab57dd9..a5d58971e 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
@@ -16,10 +16,7 @@
package com.example.android.supportv7.media;
-import android.app.PendingIntent;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
import android.graphics.Bitmap;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
@@ -32,17 +29,22 @@
* Abstraction of common playback operations of media items, such as play,
* seek, etc. Used by PlaybackManager as a backend to handle actual playback
* of media items.
+ *
+ * TODO: Introduce prepare() method and refactor subclasses accordingly.
*/
public abstract class Player {
private static final String TAG = "SampleMediaRoutePlayer";
protected static final int STATE_IDLE = 0;
- protected static final int STATE_PLAY_PENDING = 1;
- protected static final int STATE_READY = 2;
- protected static final int STATE_PLAYING = 3;
- protected static final int STATE_PAUSED = 4;
+ protected static final int STATE_PREPARING_FOR_PLAY = 1;
+ protected static final int STATE_PREPARING_FOR_PAUSE = 2;
+ protected static final int STATE_READY = 3;
+ protected static final int STATE_PLAYING = 4;
+ protected static final int STATE_PAUSED = 5;
private static final long PLAYBACK_ACTIONS = PlaybackStateCompat.ACTION_PAUSE
| PlaybackStateCompat.ACTION_PLAY;
+ private static final PlaybackStateCompat INIT_PLAYBACK_STATE = new PlaybackStateCompat.Builder()
+ .setState(PlaybackStateCompat.STATE_NONE, 0, .0f).build();
protected Callback mCallback;
protected MediaSessionCompat mMediaSession;
@@ -88,13 +90,18 @@ public static Player create(Context context, RouteInfo route, MediaSessionCompat
} else {
player = new LocalPlayer.OverlayPlayer(context);
}
- player.initMediaSession(session);
+ player.setMediaSession(session);
+ player.initMediaSession();
player.connect(route);
return player;
}
- public MediaSessionCompat getMediaSession() {
- return mMediaSession;
+ protected void initMediaSession() {
+ if (mMediaSession == null) {
+ return;
+ }
+ mMediaSession.setMetadata(null);
+ mMediaSession.setPlaybackState(INIT_PLAYBACK_STATE);
}
protected void updateMetadata() {
@@ -138,16 +145,14 @@ protected void publishState(int state) {
}
}
- private void initMediaSession(MediaSessionCompat session) {
+ private void setMediaSession(MediaSessionCompat session) {
mMediaSession = session;
- updateMetadata();
}
-
public interface Callback {
void onError();
void onCompletion();
void onPlaylistChanged();
void onPlaylistReady();
}
-}
\ No newline at end of file
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java b/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
index d47c26069..6ad4f75db 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
@@ -19,10 +19,8 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
-import android.net.Uri;
import android.os.Bundle;
import android.support.v7.media.MediaItemStatus;
-import android.support.v7.media.MediaControlIntent;
import android.support.v7.media.MediaRouter.ControlRequestCallback;
import android.support.v7.media.MediaRouter.RouteInfo;
import android.support.v7.media.MediaSessionStatus;
@@ -140,7 +138,6 @@ public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionSt
}
if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
pause();
- publishState(STATE_PAUSED);
} else {
publishState(STATE_PLAYING);
}
@@ -385,6 +382,8 @@ public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionSt
}
if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
pause();
+ } else if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PLAYING) {
+ publishState(STATE_PLAYING);
}
if (mEnqueuePending) {
mEnqueuePending = false;
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaButtonReceiver.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaButtonReceiver.java
index c2eec8ec5..d35644680 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaButtonReceiver.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaButtonReceiver.java
@@ -16,12 +16,9 @@
package com.example.android.supportv7.media;
-import com.example.android.supportv7.R;
-
import android.content.Context;
import android.content.Intent;
import android.content.BroadcastReceiver;
-import android.util.Log;
import android.view.KeyEvent;
/**
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
index 15cf19b7d..4208f5894 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
@@ -16,31 +16,26 @@
package com.example.android.supportv7.media;
-import com.example.android.supportv7.R;
-
+import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter.MalformedMimeTypeException;
import android.content.IntentSender;
import android.content.res.Resources;
-import android.graphics.Bitmap;
import android.media.AudioManager;
import android.media.MediaRouter;
import android.net.Uri;
import android.os.Bundle;
-import android.app.PendingIntent;
import android.support.v7.media.MediaControlIntent;
-import android.support.v7.media.MediaItemStatus;
+import android.support.v7.media.MediaRouteDescriptor;
import android.support.v7.media.MediaRouteProvider;
-import android.support.v7.media.MediaRouter.ControlRequestCallback;
import android.support.v7.media.MediaRouteProviderDescriptor;
-import android.support.v7.media.MediaRouteDescriptor;
+import android.support.v7.media.MediaRouter.ControlRequestCallback;
import android.support.v7.media.MediaSessionStatus;
import android.util.Log;
-import android.view.Gravity;
-import android.view.Surface;
-import android.view.SurfaceHolder;
+
+import com.example.android.supportv7.R;
import java.util.ArrayList;
@@ -56,6 +51,7 @@ final class SampleMediaRouteProvider extends MediaRouteProvider {
private static final String VARIABLE_VOLUME_BASIC_ROUTE_ID = "variable_basic";
private static final String VARIABLE_VOLUME_QUEUING_ROUTE_ID = "variable_queuing";
private static final String VARIABLE_VOLUME_SESSION_ROUTE_ID = "variable_session";
+
private static final int VOLUME_MAX = 10;
/**
@@ -135,18 +131,16 @@ final class SampleMediaRouteProvider extends MediaRouteProvider {
f6.addAction(MediaControlIntent.ACTION_GET_SESSION_STATUS);
f6.addAction(MediaControlIntent.ACTION_END_SESSION);
- CONTROL_FILTERS_BASIC = new ArrayList();
+ CONTROL_FILTERS_BASIC = new ArrayList<>();
CONTROL_FILTERS_BASIC.add(f1);
CONTROL_FILTERS_BASIC.add(f2);
CONTROL_FILTERS_BASIC.add(f3);
- CONTROL_FILTERS_QUEUING =
- new ArrayList(CONTROL_FILTERS_BASIC);
+ CONTROL_FILTERS_QUEUING = new ArrayList<>(CONTROL_FILTERS_BASIC);
CONTROL_FILTERS_QUEUING.add(f4);
CONTROL_FILTERS_QUEUING.add(f5);
- CONTROL_FILTERS_SESSION =
- new ArrayList(CONTROL_FILTERS_QUEUING);
+ CONTROL_FILTERS_SESSION = new ArrayList<>(CONTROL_FILTERS_QUEUING);
CONTROL_FILTERS_SESSION.add(f6);
}
@@ -159,7 +153,6 @@ private static void addDataTypeUnchecked(IntentFilter filter, String type) {
}
private int mVolume = 5;
- private int mEnqueueCount;
public SampleMediaRouteProvider(Context context) {
super(context);
@@ -218,6 +211,8 @@ private void publishRoutes() {
.setCanDisconnect(true)
.build();
+ Uri iconUri = Uri.parse("android.resource://com.example.android.supportv7/"
+ + R.drawable.ic_android);
MediaRouteDescriptor routeDescriptor4 = new MediaRouteDescriptor.Builder(
VARIABLE_VOLUME_SESSION_ROUTE_ID,
r.getString(R.string.variable_volume_session_route_name))
@@ -228,10 +223,10 @@ private void publishRoutes() {
.setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
.setVolumeMax(VOLUME_MAX)
.setVolume(mVolume)
+ .setIconUri(iconUri)
.build();
- MediaRouteProviderDescriptor providerDescriptor =
- new MediaRouteProviderDescriptor.Builder()
+ MediaRouteProviderDescriptor providerDescriptor = new MediaRouteProviderDescriptor.Builder()
.addRoute(routeDescriptor1)
.addRoute(routeDescriptor2)
.addRoute(routeDescriptor3)
@@ -412,7 +407,6 @@ private boolean handleEnqueue(Intent intent, ControlRequestCallback callback) {
callback.onError("Failed to open " + uri.toString(), null);
}
}
- mEnqueueCount +=1;
return true;
}
@@ -620,4 +614,4 @@ private void handleSessionStatusChange(String sid) {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
index 0a64c55fb..a40992302 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
@@ -56,6 +56,7 @@
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.SeekBar;
@@ -79,6 +80,7 @@
public class SampleMediaRouterActivity extends AppCompatActivity {
private static final String TAG = "SampleMediaRouterActivity";
private static final String DISCOVERY_FRAGMENT_TAG = "DiscoveryFragment";
+ private static final boolean ENABLE_DEFAULT_CONTROL_CHECK_BOX = false;
private MediaRouter mMediaRouter;
private MediaRouteSelector mSelector;
@@ -87,6 +89,7 @@ public class SampleMediaRouterActivity extends AppCompatActivity {
private TextView mInfoTextView;
private ListView mLibraryView;
private ListView mPlayListView;
+ private CheckBox mUseDefaultControlCheckBox;
private ImageButton mPauseResumeButton;
private ImageButton mStopButton;
private SeekBar mSeekBar;
@@ -308,6 +311,10 @@ public void onItemClick(AdapterView> parent, View view, int position, long id)
mInfoTextView = (TextView) findViewById(R.id.info);
+ mUseDefaultControlCheckBox = (CheckBox) findViewById(R.id.custom_control_view_checkbox);
+ if (ENABLE_DEFAULT_CONTROL_CHECK_BOX) {
+ mUseDefaultControlCheckBox.setVisibility(View.VISIBLE);
+ }
mPauseResumeButton = (ImageButton)findViewById(R.id.pause_resume_button);
mPauseResumeButton.setOnClickListener(new OnClickListener() {
@Override
@@ -518,7 +525,7 @@ public boolean onCreateOptionsMenu(Menu menu) {
mediaRouteActionProvider.setDialogFactory(new MediaRouteDialogFactory() {
@Override
public MediaRouteControllerDialogFragment onCreateControllerDialogFragment() {
- return new ControllerDialogFragment(mPlayer);
+ return new ControllerDialogFragment(mPlayer, mUseDefaultControlCheckBox);
}
});
@@ -734,20 +741,23 @@ public static class LightWithDarkActionBar extends SampleMediaRouterActivity {
public static class ControllerDialogFragment extends MediaRouteControllerDialogFragment {
private MediaRouteControllerDialog mControllerDialog;
private Player mPlayer;
+ private CheckBox mUseDefaultControlCheckBox;
public ControllerDialogFragment() {
super();
}
- public ControllerDialogFragment(Player player) {
+ public ControllerDialogFragment(Player player, CheckBox customControlViewCheckBox) {
mPlayer = player;
+ this.mUseDefaultControlCheckBox = customControlViewCheckBox;
}
@Override
public MediaRouteControllerDialog onCreateControllerDialog(
Context context, Bundle savedInstanceState) {
- mControllerDialog = super.onCreateControllerDialog(context,
- savedInstanceState);
+ mControllerDialog = this.mUseDefaultControlCheckBox.isChecked()
+ ? super.onCreateControllerDialog(context, savedInstanceState)
+ : new MyMediaRouteControllerDialog(context);
mControllerDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SessionManager.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SessionManager.java
index 1c00192de..6fab2eb6b 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SessionManager.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SessionManager.java
@@ -349,6 +349,8 @@ private void updatePlaybackState() {
if (mCallback != null) {
mCallback.onItemChanged(item);
}
+ } else {
+ mPlayer.initMediaSession();
}
updateStatus();
}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/AnimatedRecyclerView.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/AnimatedRecyclerView.java
index af5c6532d..6714f6d02 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/AnimatedRecyclerView.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/AnimatedRecyclerView.java
@@ -15,13 +15,20 @@
*/
package com.example.android.supportv7.widget;
-import android.support.v4.util.ArrayMap;
-import android.widget.CompoundButton;
import com.example.android.supportv7.R;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
+import android.os.Build;
import android.os.Bundle;
+import android.support.v4.util.ArrayMap;
import android.support.v4.view.MenuItemCompat;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.view.ViewPropertyAnimatorListener;
+import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;
import android.util.TypedValue;
@@ -30,10 +37,10 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
+import android.widget.CompoundButton;
import android.widget.TextView;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
public class AnimatedRecyclerView extends Activity {
@@ -49,6 +56,7 @@ public class AnimatedRecyclerView extends Activity {
boolean mAnimationsEnabled = true;
boolean mPredictiveAnimationsEnabled = true;
RecyclerView.ItemAnimator mCachedAnimator = null;
+ boolean mEnableInPlaceChange = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -57,7 +65,9 @@ protected void onCreate(Bundle savedInstanceState) {
ViewGroup container = (ViewGroup) findViewById(R.id.container);
mRecyclerView = new RecyclerView(this);
- mCachedAnimator = mRecyclerView.getItemAnimator();
+ mCachedAnimator = createAnimator();
+ mCachedAnimator.setChangeDuration(2000);
+ mRecyclerView.setItemAnimator(mCachedAnimator);
mRecyclerView.setLayoutManager(new MyLayoutManager(this));
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
@@ -91,14 +101,241 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
}
});
- CheckBox enableChangeAnimations =
- (CheckBox) findViewById(R.id.enableChangeAnimations);
- enableChangeAnimations.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ CheckBox enableInPlaceChange = (CheckBox) findViewById(R.id.enableInPlaceChange);
+ enableInPlaceChange.setChecked(mEnableInPlaceChange);
+ enableInPlaceChange.setOnCheckedChangeListener(
+ new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ mEnableInPlaceChange = isChecked;
+ }
+ });
+ }
+
+ private RecyclerView.ItemAnimator createAnimator() {
+ return new DefaultItemAnimator() {
+ List mPendingChangeAnimations = new ArrayList<>();
+ ArrayMap mRunningAnimations
+ = new ArrayMap<>();
+ ArrayMap mPendingSettleList = new ArrayMap<>();
+
@Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- mCachedAnimator.setSupportsChangeAnimations(isChecked);
+ public void runPendingAnimations() {
+ super.runPendingAnimations();
+ for (ItemChangeAnimator anim : mPendingChangeAnimations) {
+ anim.start();
+ mRunningAnimations.put(anim.mViewHolder, anim);
+ }
+ mPendingChangeAnimations.clear();
+ for (int i = mPendingSettleList.size() - 1; i >=0; i--) {
+ final MyViewHolder vh = mPendingSettleList.keyAt(i);
+ final long duration = mPendingSettleList.valueAt(i);
+ ViewCompat.animate(vh.textView).translationX(0f).alpha(1f)
+ .setDuration(duration).setListener(
+ new ViewPropertyAnimatorListener() {
+ @Override
+ public void onAnimationStart(View view) {
+ dispatchAnimationStarted(vh);
+ }
+
+ @Override
+ public void onAnimationEnd(View view) {
+ ViewCompat.setTranslationX(vh.textView, 0f);
+ ViewCompat.setAlpha(vh.textView, 1f);
+ dispatchAnimationFinished(vh);
+ }
+
+ @Override
+ public void onAnimationCancel(View view) {
+
+ }
+ }).start();
+ }
+ mPendingSettleList.clear();
}
- });
+
+ @Override
+ public ItemHolderInfo recordPreLayoutInformation(RecyclerView.State state,
+ RecyclerView.ViewHolder viewHolder,
+ @AdapterChanges int changeFlags, List
+
+
+
+
+
+
+
@@ -154,6 +163,15 @@
+
+
+
+
+
+
+
@@ -181,5 +199,14 @@
+
+
+
+
+
+
+
diff --git a/samples/SupportDesignDemos/proguard.flags b/samples/SupportDesignDemos/proguard.flags
new file mode 100644
index 000000000..9ebd7374d
--- /dev/null
+++ b/samples/SupportDesignDemos/proguard.flags
@@ -0,0 +1,7 @@
+-keep public class * extends android.support.design.widget.CoordinatorLayout$Behavior {
+ public (android.content.Context, android.util.AttributeSet);
+}
+
+-keep public class * extends android.support.v7.widget.LinearLayoutManager {
+ public (android.content.Context, android.util.AttributeSet, int, int);
+}
diff --git a/samples/SupportDesignDemos/res/layout/action_layout.xml b/samples/SupportDesignDemos/res/layout/action_layout.xml
new file mode 100644
index 000000000..a266d5104
--- /dev/null
+++ b/samples/SupportDesignDemos/res/layout/action_layout.xml
@@ -0,0 +1,23 @@
+
+
+
diff --git a/samples/SupportDesignDemos/res/layout/design_appbar_toolbar_collapse_scroll_with_swiperefresh.xml b/samples/SupportDesignDemos/res/layout/design_appbar_toolbar_collapse_scroll_with_swiperefresh.xml
new file mode 100644
index 000000000..d0572afac
--- /dev/null
+++ b/samples/SupportDesignDemos/res/layout/design_appbar_toolbar_collapse_scroll_with_swiperefresh.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/SupportDesignDemos/res/layout/design_appbar_toolbar_scroll_tabs_scroll_snap.xml b/samples/SupportDesignDemos/res/layout/design_appbar_toolbar_scroll_tabs_scroll_snap.xml
new file mode 100644
index 000000000..b559ca370
--- /dev/null
+++ b/samples/SupportDesignDemos/res/layout/design_appbar_toolbar_scroll_tabs_scroll_snap.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/SupportDesignDemos/res/layout/design_bottom_sheet.xml b/samples/SupportDesignDemos/res/layout/design_bottom_sheet.xml
new file mode 100644
index 000000000..56197eaec
--- /dev/null
+++ b/samples/SupportDesignDemos/res/layout/design_bottom_sheet.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/SupportDesignDemos/res/layout/design_text_input.xml b/samples/SupportDesignDemos/res/layout/design_text_input.xml
index 4561df125..32260746f 100644
--- a/samples/SupportDesignDemos/res/layout/design_text_input.xml
+++ b/samples/SupportDesignDemos/res/layout/design_text_input.xml
@@ -36,6 +36,24 @@
+
+
+
+
+
+
+
+
-
+ android:layout_marginTop="8dp"
+ app:counterEnabled="true"
+ app:counterMaxLength="30">
-
+
+
+
\ No newline at end of file
diff --git a/samples/SupportDesignDemos/res/menu/navigation.xml b/samples/SupportDesignDemos/res/menu/navigation.xml
index b399ef3a9..6425b1893 100644
--- a/samples/SupportDesignDemos/res/menu/navigation.xml
+++ b/samples/SupportDesignDemos/res/menu/navigation.xml
@@ -14,7 +14,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-